diff options
author | André Fabian Silva Delgado <emulatorman@parabola.nu> | 2016-03-25 03:53:42 -0300 |
---|---|---|
committer | André Fabian Silva Delgado <emulatorman@parabola.nu> | 2016-03-25 03:53:42 -0300 |
commit | 03dd4cb26d967f9588437b0fc9cc0e8353322bb7 (patch) | |
tree | fa581f6dc1c0596391690d1f67eceef3af8246dc /drivers/media | |
parent | d4e493caf788ef44982e131ff9c786546904d934 (diff) |
Linux-libre 4.5-gnu
Diffstat (limited to 'drivers/media')
402 files changed, 6497 insertions, 4444 deletions
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 3ef3d6c6b..a8518fb3b 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -9,7 +9,7 @@ menuconfig MEDIA_SUPPORT If you want to use Webcams, Video grabber devices and/or TV devices enable this option and other options below. Additional info and docs are available on the web at - <http://linuxtv.org> + <https://linuxtv.org> if MEDIA_SUPPORT @@ -51,7 +51,7 @@ config MEDIA_RADIO_SUPPORT Enable AM/FM radio support. Additional info and docs are available on the web at - <http://linuxtv.org> + <https://linuxtv.org> Say Y when you have a board with radio support. @@ -97,7 +97,6 @@ config MEDIA_CONTROLLER config MEDIA_CONTROLLER_DVB bool "Enable Media controller for DVB (EXPERIMENTAL)" depends on MEDIA_CONTROLLER - depends on BROKEN ---help--- Enable the media controller API support for DVB. diff --git a/drivers/media/common/cx2341x.c b/drivers/media/common/cx2341x.c index c07b9db51..5e4afa013 100644 --- a/drivers/media/common/cx2341x.c +++ b/drivers/media/common/cx2341x.c @@ -27,7 +27,7 @@ #include <linux/videodev2.h> #include <media/tuner.h> -#include <media/cx2341x.h> +#include <media/drv-intf/cx2341x.h> #include <media/v4l2-common.h> MODULE_DESCRIPTION("cx23415/6/8 driver"); diff --git a/drivers/media/common/saa7146/saa7146_core.c b/drivers/media/common/saa7146/saa7146_core.c index 1ff9f5323..9f7c5b0a6 100644 --- a/drivers/media/common/saa7146/saa7146_core.c +++ b/drivers/media/common/saa7146/saa7146_core.c @@ -20,7 +20,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include <media/saa7146.h> +#include <media/drv-intf/saa7146.h> #include <linux/module.h> static int saa7146_num; diff --git a/drivers/media/common/saa7146/saa7146_fops.c b/drivers/media/common/saa7146/saa7146_fops.c index df1e8c975..930d2c94d 100644 --- a/drivers/media/common/saa7146/saa7146_fops.c +++ b/drivers/media/common/saa7146/saa7146_fops.c @@ -1,6 +1,6 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include <media/saa7146_vv.h> +#include <media/drv-intf/saa7146_vv.h> #include <linux/module.h> /****************************************************************************/ diff --git a/drivers/media/common/saa7146/saa7146_hlp.c b/drivers/media/common/saa7146/saa7146_hlp.c index 3dc6a838c..6ebcbc645 100644 --- a/drivers/media/common/saa7146/saa7146_hlp.c +++ b/drivers/media/common/saa7146/saa7146_hlp.c @@ -2,7 +2,7 @@ #include <linux/kernel.h> #include <linux/export.h> -#include <media/saa7146_vv.h> +#include <media/drv-intf/saa7146_vv.h> static void calculate_output_format_register(struct saa7146_dev* saa, u32 palette, u32* clip_format) { diff --git a/drivers/media/common/saa7146/saa7146_i2c.c b/drivers/media/common/saa7146/saa7146_i2c.c index 220271981..239a2db35 100644 --- a/drivers/media/common/saa7146/saa7146_i2c.c +++ b/drivers/media/common/saa7146/saa7146_i2c.c @@ -1,6 +1,6 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include <media/saa7146_vv.h> +#include <media/drv-intf/saa7146_vv.h> static u32 saa7146_i2c_func(struct i2c_adapter *adapter) { diff --git a/drivers/media/common/saa7146/saa7146_vbi.c b/drivers/media/common/saa7146/saa7146_vbi.c index 2da995758..49237518d 100644 --- a/drivers/media/common/saa7146/saa7146_vbi.c +++ b/drivers/media/common/saa7146/saa7146_vbi.c @@ -1,4 +1,4 @@ -#include <media/saa7146_vv.h> +#include <media/drv-intf/saa7146_vv.h> static int vbi_pixel_to_capture = 720 * 2; diff --git a/drivers/media/common/saa7146/saa7146_video.c b/drivers/media/common/saa7146/saa7146_video.c index 30779498c..ea2f3bf73 100644 --- a/drivers/media/common/saa7146/saa7146_video.c +++ b/drivers/media/common/saa7146/saa7146_video.c @@ -1,6 +1,6 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include <media/saa7146_vv.h> +#include <media/drv-intf/saa7146_vv.h> #include <media/v4l2-event.h> #include <media/v4l2-ctrls.h> #include <linux/module.h> @@ -502,7 +502,7 @@ static int vidioc_s_fbuf(struct file *file, void *fh, const struct v4l2_framebuf /* check if overlay is running */ if (IS_OVERLAY_ACTIVE(fh) != 0) { if (vv->video_fh != fh) { - DEB_D("refusing to change framebuffer informations while overlay is active in another open\n"); + DEB_D("refusing to change framebuffer information while overlay is active in another open\n"); return -EBUSY; } } diff --git a/drivers/media/common/siano/smsdvb-main.c b/drivers/media/common/siano/smsdvb-main.c index f4305ae80..d31f46883 100644 --- a/drivers/media/common/siano/smsdvb-main.c +++ b/drivers/media/common/siano/smsdvb-main.c @@ -617,6 +617,7 @@ static void smsdvb_media_device_unregister(struct smsdvb_client_t *client) if (!coredev->media_dev) return; media_device_unregister(coredev->media_dev); + media_device_cleanup(coredev->media_dev); kfree(coredev->media_dev); coredev->media_dev = NULL; #endif @@ -1183,7 +1184,11 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev, if (smsdvb_debugfs_create(client) < 0) pr_info("failed to create debugfs node\n"); - dvb_create_media_graph(&client->adapter); + rc = dvb_create_media_graph(&client->adapter, true); + if (rc < 0) { + pr_err("dvb_create_media_graph failed %d\n", rc); + goto client_error; + } pr_info("DVB interface registered.\n"); return 0; diff --git a/drivers/media/common/siano/smsir.h b/drivers/media/common/siano/smsir.h index fc8b7925c..d9abd96ef 100644 --- a/drivers/media/common/siano/smsir.h +++ b/drivers/media/common/siano/smsir.h @@ -30,8 +30,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #include <linux/input.h> #include <media/rc-core.h> -#define IR_DEFAULT_TIMEOUT 100 - struct smscore_device_t; struct ir_t { diff --git a/drivers/media/dvb-core/demux.h b/drivers/media/dvb-core/demux.h index ccc1f43cb..6d3b95b89 100644 --- a/drivers/media/dvb-core/demux.h +++ b/drivers/media/dvb-core/demux.h @@ -32,6 +32,49 @@ #include <linux/time.h> #include <linux/dvb/dmx.h> +/** + * DOC: Digital TV Demux + * + * The Kernel Digital TV Demux kABI defines a driver-internal interface for + * registering low-level, hardware specific driver to a hardware independent + * demux layer. It is only of interest for Digital TV device driver writers. + * The header file for this kABI is named demux.h and located in + * drivers/media/dvb-core. + * + * The demux kABI should be implemented for each demux in the system. It is + * used to select the TS source of a demux and to manage the demux resources. + * When the demux client allocates a resource via the demux kABI, it receives + * a pointer to the kABI of that resource. + * + * Each demux receives its TS input from a DVB front-end or from memory, as + * set via this demux kABI. In a system with more than one front-end, the kABI + * can be used to select one of the DVB front-ends as a TS source for a demux, + * unless this is fixed in the HW platform. + * + * The demux kABI only controls front-ends regarding to their connections with + * demuxes; the kABI used to set the other front-end parameters, such as + * tuning, are devined via the Digital TV Frontend kABI. + * + * The functions that implement the abstract interface demux should be defined + * static or module private and registered to the Demux core for external + * access. It is not necessary to implement every function in the struct + * &dmx_demux. For example, a demux interface might support Section filtering, + * but not PES filtering. The kABI client is expected to check the value of any + * function pointer before calling the function: the value of NULL means + * that the function is not available. + * + * Whenever the functions of the demux API modify shared data, the + * possibilities of lost update and race condition problems should be + * addressed, e.g. by protecting parts of code with mutexes. + * + * Note that functions called from a bottom half context must not sleep. + * Even a simple memory allocation without using %GFP_ATOMIC can result in a + * kernel thread being put to sleep if swapping is needed. For example, the + * Linux Kernel calls the functions of a network device interface from a + * bottom half context. Thus, if a demux kABI function is called from network + * device code, the function must not sleep. + */ + /* * Common definitions */ @@ -187,8 +230,28 @@ struct dmx_section_feed { int (*stop_filtering)(struct dmx_section_feed *feed); }; -/* - * Callback functions +/** + * DOC: Demux Callback + * + * This kernel-space API comprises the callback functions that deliver filtered + * data to the demux client. Unlike the other DVB kABIs, these functions are + * provided by the client and called from the demux code. + * + * The function pointers of this abstract interface are not packed into a + * structure as in the other demux APIs, because the callback functions are + * registered and used independent of each other. As an example, it is possible + * for the API client to provide several callback functions for receiving TS + * packets and no callbacks for PES packets or sections. + * + * The functions that implement the callback API need not be re-entrant: when + * a demux driver calls one of these functions, the driver is not allowed to + * call the function again before the original call returns. If a callback is + * triggered by a hardware interrupt, it is recommended to use the Linux + * bottom half mechanism or start a tasklet instead of making the callback + * function call directly from a hardware interrupt. + * + * This mechanism is implemented by dmx_ts_cb() and dmx_section_cb() + * callbacks. */ /** diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c index ea9abde90..a168cbe1c 100644 --- a/drivers/media/dvb-core/dmxdev.c +++ b/drivers/media/dvb-core/dmxdev.c @@ -1244,9 +1244,9 @@ int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter) } dvb_register_device(dvb_adapter, &dmxdev->dvbdev, &dvbdev_demux, dmxdev, - DVB_DEVICE_DEMUX); + DVB_DEVICE_DEMUX, dmxdev->filternum); dvb_register_device(dvb_adapter, &dmxdev->dvr_dvbdev, &dvbdev_dvr, - dmxdev, DVB_DEVICE_DVR); + dmxdev, DVB_DEVICE_DVR, dmxdev->filternum); dvb_ringbuffer_init(&dmxdev->dvr_buffer, NULL, 8192); diff --git a/drivers/media/dvb-core/dvb-usb-ids.h b/drivers/media/dvb-core/dvb-usb-ids.h index 0a46580b5..1c1c298d2 100644 --- a/drivers/media/dvb-core/dvb-usb-ids.h +++ b/drivers/media/dvb-core/dvb-usb-ids.h @@ -389,4 +389,5 @@ #define USB_PID_PCTV_2002E_SE 0x025d #define USB_PID_SVEON_STV27 0xd3af #define USB_PID_TURBOX_DTT_2000 0xd3a4 +#define USB_PID_WINTV_SOLOHD 0x0264 #endif diff --git a/drivers/media/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb-core/dvb_ca_en50221.c index fb66184dc..f82cd1ff4 100644 --- a/drivers/media/dvb-core/dvb_ca_en50221.c +++ b/drivers/media/dvb-core/dvb_ca_en50221.c @@ -1695,7 +1695,7 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, pubca->private = ca; /* register the DVB device */ - ret = dvb_register_device(dvb_adapter, &ca->dvbdev, &dvbdev_ca, ca, DVB_DEVICE_CA); + ret = dvb_register_device(dvb_adapter, &ca->dvbdev, &dvbdev_ca, ca, DVB_DEVICE_CA, 0); if (ret) goto free_slot_info; diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index e2a383317..400806453 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -622,7 +622,7 @@ static int dvb_enable_media_tuner(struct dvb_frontend *fe) struct media_device *mdev = adapter->mdev; struct media_entity *entity, *source; struct media_link *link, *found_link = NULL; - int i, ret, n_links = 0, active_links = 0; + int ret, n_links = 0, active_links = 0; fepriv->pipe_start_entity = NULL; @@ -632,8 +632,7 @@ static int dvb_enable_media_tuner(struct dvb_frontend *fe) entity = fepriv->dvbdev->entity; fepriv->pipe_start_entity = entity; - for (i = 0; i < entity->num_links; i++) { - link = &entity->links[i]; + list_for_each_entry(link, &entity->links, list) { if (link->sink->entity == entity) { found_link = link; n_links++; @@ -659,13 +658,11 @@ static int dvb_enable_media_tuner(struct dvb_frontend *fe) source = found_link->source->entity; fepriv->pipe_start_entity = source; - for (i = 0; i < source->num_links; i++) { + list_for_each_entry(link, &source->links, list) { struct media_entity *sink; int flags = 0; - link = &source->links[i]; sink = link->sink->entity; - if (sink == entity) flags = MEDIA_LNK_FL_ENABLED; @@ -891,21 +888,21 @@ static void dvb_frontend_stop(struct dvb_frontend *fe) } /* - * Sleep until gettimeofday() > waketime + add_usec - * This needs to be as precise as possible, but as the delay is - * usually between 2ms and 32ms, it is done using a scheduled msleep - * followed by usleep (normally a busy-wait loop) for the remainder + * Sleep for the amount of time given by add_usec parameter + * + * This needs to be as precise as possible, as it affects the detection of + * the dish tone command at the satellite subsystem. The precision is improved + * by using a scheduled msleep followed by udelay for the remainder. */ void dvb_frontend_sleep_until(ktime_t *waketime, u32 add_usec) { - s32 delta, newdelta; + s32 delta; - ktime_add_us(*waketime, add_usec); + *waketime = ktime_add_us(*waketime, add_usec); delta = ktime_us_delta(ktime_get_real(), *waketime); if (delta > 2500) { msleep((delta - 1500) / 1000); - newdelta = ktime_us_delta(ktime_get_real(), *waketime); - delta = (newdelta > delta) ? 0 : newdelta; + delta = ktime_us_delta(ktime_get_real(), *waketime); } if (delta > 0) udelay(delta); @@ -2710,6 +2707,11 @@ int dvb_frontend_resume(struct dvb_frontend *fe) else if (fe->ops.tuner_ops.init) ret = fe->ops.tuner_ops.init(fe); + if (fe->ops.set_tone && fepriv->tone != -1) + fe->ops.set_tone(fe, fepriv->tone); + if (fe->ops.set_voltage && fepriv->voltage != -1) + fe->ops.set_voltage(fe, fepriv->voltage); + fe->exit = DVB_FE_NO_EXIT; fepriv->state = FESTATE_RETUNE; dvb_frontend_wakeup(fe); @@ -2757,7 +2759,7 @@ int dvb_register_frontend(struct dvb_adapter* dvb, fe->dvb->num, fe->id, fe->ops.info.name); dvb_register_device (fe->dvb, &fepriv->dvbdev, &dvbdev_template, - fe, DVB_DEVICE_FRONTEND); + fe, DVB_DEVICE_FRONTEND, 0); /* * Initialize the cache to the proper values according with the diff --git a/drivers/media/dvb-core/dvb_frontend.h b/drivers/media/dvb-core/dvb_frontend.h index 97661b2f2..458bcce20 100644 --- a/drivers/media/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb-core/dvb_frontend.h @@ -42,6 +42,29 @@ #include "dvbdev.h" +/** + * DOC: Digital TV Frontend + * + * The Digital TV Frontend kABI defines a driver-internal interface for + * registering low-level, hardware specific driver to a hardware independent + * frontend layer. It is only of interest for Digital TV device driver writers. + * The header file for this API is named dvb_frontend.h and located in + * drivers/media/dvb-core. + * + * Before using the Digital TV frontend core, the bridge driver should attach + * the frontend demod, tuner and SEC devices and call dvb_register_frontend(), + * in order to register the new frontend at the subsystem. At device + * detach/removal, the bridge driver should call dvb_unregister_frontend() to + * remove the frontend from the core and then dvb_frontend_detach() to free the + * memory allocated by the frontend drivers. + * + * The drivers should also call dvb_frontend_suspend() as part of their + * handler for the &device_driver.suspend(), and dvb_frontend_resume() as + * part of their handler for &device_driver.resume(). + * + * A few other optional functions are provided to handle some special cases. + */ + /* * Maximum number of Delivery systems per frontend. It * should be smaller or equal to 32 @@ -112,16 +135,6 @@ struct analog_parameters { u64 std; }; -enum tuner_param { - DVBFE_TUNER_FREQUENCY = (1 << 0), - DVBFE_TUNER_TUNERSTEP = (1 << 1), - DVBFE_TUNER_IFFREQ = (1 << 2), - DVBFE_TUNER_BANDWIDTH = (1 << 3), - DVBFE_TUNER_REFCLOCK = (1 << 4), - DVBFE_TUNER_IQSENSE = (1 << 5), - DVBFE_TUNER_DUMMY = (1 << 31) -}; - /** * enum dvbfe_algo - defines the algorithm used to tune into a channel * @@ -152,15 +165,6 @@ enum dvbfe_algo { DVBFE_ALGO_RECOVERY = (1 << 31) }; -struct tuner_state { - u32 frequency; - u32 tunerstep; - u32 ifreq; - u32 bandwidth; - u32 iqsense; - u32 refclock; -}; - /** * enum dvbfe_search - search callback possible return status * @@ -209,12 +213,12 @@ enum dvbfe_search { * are stored at @dvb_frontend.dtv_property_cache;. The * tuner demod can change the parameters to reflect the * changes needed for the channel to be tuned, and - * update statistics. + * update statistics. This is the recommended way to set + * the tuner parameters and should be used on newer + * drivers. * @set_analog_params: callback function used to tune into an analog TV * channel on hybrid tuners. It passes @analog_parameters; * to the driver. - * @calc_regs: callback function used to pass register data settings - * for simple tuners. * @set_config: callback function used to send some tuner-specific * parameters. * @get_frequency: get the actual tuned frequency @@ -227,16 +231,10 @@ enum dvbfe_search { * via DVBv5 API (@dvb_frontend.dtv_property_cache;). * @get_afc: Used only by analog TV core. Reports the frequency * drift due to AFC. - * @set_frequency: Set a new frequency. Please notice that using - * set_params is preferred. - * @set_bandwidth: Set a new frequency. Please notice that using - * set_params is preferred. - * @set_state: callback function used on some legacy drivers that - * don't implement set_params in order to set properties. - * Shouldn't be used on new drivers. - * @get_state: callback function used to get properties by some - * legacy drivers that don't implement set_params. - * Shouldn't be used on new drivers. + * @calc_regs: callback function used to pass register data settings + * for simple tuners. Shouldn't be used on newer drivers. + * @set_frequency: Set a new frequency. Shouldn't be used on newer drivers. + * @set_bandwidth: Set a new frequency. Shouldn't be used on newer drivers. * * NOTE: frequencies used on get_frequency and set_frequency are in Hz for * terrestrial/cable or kHz for satellite. @@ -252,14 +250,10 @@ struct dvb_tuner_ops { int (*suspend)(struct dvb_frontend *fe); int (*resume)(struct dvb_frontend *fe); - /** This is for simple PLLs - set all parameters in one go. */ + /* This is the recomended way to set the tuner */ int (*set_params)(struct dvb_frontend *fe); int (*set_analog_params)(struct dvb_frontend *fe, struct analog_parameters *p); - /** This is support for demods like the mt352 - fills out the supplied buffer with what to write. */ - int (*calc_regs)(struct dvb_frontend *fe, u8 *buf, int buf_len); - - /** This is to allow setting tuner-specific configs */ int (*set_config)(struct dvb_frontend *fe, void *priv_cfg); int (*get_frequency)(struct dvb_frontend *fe, u32 *frequency); @@ -272,17 +266,23 @@ struct dvb_tuner_ops { int (*get_rf_strength)(struct dvb_frontend *fe, u16 *strength); int (*get_afc)(struct dvb_frontend *fe, s32 *afc); - /** These are provided separately from set_params in order to facilitate silicon - * tuners which require sophisticated tuning loops, controlling each parameter separately. */ - int (*set_frequency)(struct dvb_frontend *fe, u32 frequency); - int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth); + /* + * This is support for demods like the mt352 - fills out the supplied + * buffer with what to write. + * + * Don't use on newer drivers. + */ + int (*calc_regs)(struct dvb_frontend *fe, u8 *buf, int buf_len); /* - * These are provided separately from set_params in order to facilitate silicon - * tuners which require sophisticated tuning loops, controlling each parameter separately. + * These are provided separately from set_params in order to + * facilitate silicon tuners which require sophisticated tuning loops, + * controlling each parameter separately. + * + * Don't use on newer drivers. */ - int (*set_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state); - int (*get_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state); + int (*set_frequency)(struct dvb_frontend *fe, u32 frequency); + int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth); }; /** @@ -404,6 +404,11 @@ struct dtv_frontend_properties; * FE_ENABLE_HIGH_LNB_VOLTAGE ioctl (only Satellite). * @dishnetwork_send_legacy_command: callback function to implement the * FE_DISHNETWORK_SEND_LEGACY_CMD ioctl (only Satellite). + * Drivers should not use this, except when the DVB + * core emulation fails to provide proper support (e.g. + * if set_voltage() takes more than 8ms to work), and + * when backward compatibility with this legacy API is + * required. * @i2c_gate_ctrl: controls the I2C gate. Newer drivers should use I2C * mux support instead. * @ts_bus_ctrl: callback function used to take control of the TS bus. @@ -466,7 +471,8 @@ struct dvb_frontend_ops { int (*ts_bus_ctrl)(struct dvb_frontend* fe, int acquire); int (*set_lna)(struct dvb_frontend *); - /* These callbacks are for devices that implement their own + /* + * These callbacks are for devices that implement their own * tuning algorithms, rather than a simple swzigzag */ enum dvbfe_search (*search)(struct dvb_frontend *fe); @@ -682,17 +688,126 @@ struct dvb_frontend { unsigned int exit; }; -extern int dvb_register_frontend(struct dvb_adapter *dvb, +/** + * dvb_register_frontend() - Registers a DVB frontend at the adapter + * + * @dvb: pointer to the dvb adapter + * @fe: pointer to the frontend struct + * + * Allocate and initialize the private data needed by the frontend core to + * manage the frontend and calls dvb_register_device() to register a new + * frontend. It also cleans the property cache that stores the frontend + * parameters and selects the first available delivery system. + */ +int dvb_register_frontend(struct dvb_adapter *dvb, struct dvb_frontend *fe); -extern int dvb_unregister_frontend(struct dvb_frontend *fe); +/** + * dvb_unregister_frontend() - Unregisters a DVB frontend + * + * @fe: pointer to the frontend struct + * + * Stops the frontend kthread, calls dvb_unregister_device() and frees the + * private frontend data allocated by dvb_register_frontend(). + * + * NOTE: This function doesn't frees the memory allocated by the demod, + * by the SEC driver and by the tuner. In order to free it, an explicit call to + * dvb_frontend_detach() is needed, after calling this function. + */ +int dvb_unregister_frontend(struct dvb_frontend *fe); -extern void dvb_frontend_detach(struct dvb_frontend *fe); +/** + * dvb_frontend_detach() - Detaches and frees frontend specific data + * + * @fe: pointer to the frontend struct + * + * This function should be called after dvb_unregister_frontend(). It + * calls the SEC, tuner and demod release functions: + * &dvb_frontend_ops.release_sec, &dvb_frontend_ops.tuner_ops.release, + * &dvb_frontend_ops.analog_ops.release and &dvb_frontend_ops.release. + * + * If the driver is compiled with CONFIG_MEDIA_ATTACH, it also decreases + * the module reference count, needed to allow userspace to remove the + * previously used DVB frontend modules. + */ +void dvb_frontend_detach(struct dvb_frontend *fe); + +/** + * dvb_frontend_suspend() - Suspends a Digital TV frontend + * + * @fe: pointer to the frontend struct + * + * This function prepares a Digital TV frontend to suspend. + * + * In order to prepare the tuner to suspend, if + * &dvb_frontend_ops.tuner_ops.suspend() is available, it calls it. Otherwise, + * it will call &dvb_frontend_ops.tuner_ops.sleep(), if available. + * + * It will also call &dvb_frontend_ops.sleep() to put the demod to suspend. + * + * The drivers should also call dvb_frontend_suspend() as part of their + * handler for the &device_driver.suspend(). + */ +int dvb_frontend_suspend(struct dvb_frontend *fe); + +/** + * dvb_frontend_resume() - Resumes a Digital TV frontend + * + * @fe: pointer to the frontend struct + * + * This function resumes the usual operation of the tuner after resume. + * + * In order to resume the frontend, it calls the demod &dvb_frontend_ops.init(). + * + * If &dvb_frontend_ops.tuner_ops.resume() is available, It, it calls it. + * Otherwise,t will call &dvb_frontend_ops.tuner_ops.init(), if available. + * + * Once tuner and demods are resumed, it will enforce that the SEC voltage and + * tone are restored to their previous values and wake up the frontend's + * kthread in order to retune the frontend. + * + * The drivers should also call dvb_frontend_resume() as part of their + * handler for the &device_driver.resume(). + */ +int dvb_frontend_resume(struct dvb_frontend *fe); -extern void dvb_frontend_reinitialise(struct dvb_frontend *fe); -extern int dvb_frontend_suspend(struct dvb_frontend *fe); -extern int dvb_frontend_resume(struct dvb_frontend *fe); +/** + * dvb_frontend_reinitialise() - forces a reinitialisation at the frontend + * + * @fe: pointer to the frontend struct + * + * Calls &dvb_frontend_ops.init() and &dvb_frontend_ops.tuner_ops.init(), + * and resets SEC tone and voltage (for Satellite systems). + * + * NOTE: Currently, this function is used only by one driver (budget-av). + * It seems to be due to address some special issue with that specific + * frontend. + */ +void dvb_frontend_reinitialise(struct dvb_frontend *fe); -extern void dvb_frontend_sleep_until(ktime_t *waketime, u32 add_usec); +/** + * dvb_frontend_sleep_until() - Sleep for the amount of time given by + * add_usec parameter + * + * @waketime: pointer to a struct ktime_t + * @add_usec: time to sleep, in microseconds + * + * This function is used to measure the time required for the + * %FE_DISHNETWORK_SEND_LEGACY_CMD ioctl to work. It needs to be as precise + * as possible, as it affects the detection of the dish tone command at the + * satellite subsystem. + * + * Its used internally by the DVB frontend core, in order to emulate + * %FE_DISHNETWORK_SEND_LEGACY_CMD using the &dvb_frontend_ops.set_voltage() + * callback. + * + * NOTE: it should not be used at the drivers, as the emulation for the + * legacy callback is provided by the Kernel. The only situation where this + * should be at the drivers is when there are some bugs at the hardware that + * would prevent the core emulation to work. On such cases, the driver would + * be writing a &dvb_frontend_ops.dishnetwork_send_legacy_command() and + * calling this function directly. + */ +void dvb_frontend_sleep_until(ktime_t *waketime, u32 add_usec); #endif diff --git a/drivers/media/dvb-core/dvb_net.c b/drivers/media/dvb-core/dvb_net.c index ce4332e80..ce6a711b4 100644 --- a/drivers/media/dvb-core/dvb_net.c +++ b/drivers/media/dvb-core/dvb_net.c @@ -1502,6 +1502,6 @@ int dvb_net_init (struct dvb_adapter *adap, struct dvb_net *dvbnet, dvbnet->state[i] = 0; return dvb_register_device(adap, &dvbnet->dvbdev, &dvbdev_net, - dvbnet, DVB_DEVICE_NET); + dvbnet, DVB_DEVICE_NET, 0); } EXPORT_SYMBOL(dvb_net_init); diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c index 13bb57f04..560450a0b 100644 --- a/drivers/media/dvb-core/dvbdev.c +++ b/drivers/media/dvb-core/dvbdev.c @@ -34,6 +34,9 @@ #include <linux/mutex.h> #include "dvbdev.h" +/* Due to enum tuner_pad_index */ +#include <media/tuner.h> + static DEFINE_MUTEX(dvbdev_mutex); static int dvbdev_debug; @@ -180,102 +183,255 @@ skip: return -ENFILE; } -static void dvb_register_media_device(struct dvb_device *dvbdev, - int type, int minor) +static void dvb_media_device_free(struct dvb_device *dvbdev) { #if defined(CONFIG_MEDIA_CONTROLLER_DVB) - int ret = 0, npads; + if (dvbdev->entity) { + media_device_unregister_entity(dvbdev->entity); + kfree(dvbdev->entity); + kfree(dvbdev->pads); + dvbdev->entity = NULL; + dvbdev->pads = NULL; + } - if (!dvbdev->adapter->mdev) - return; + if (dvbdev->tsout_entity) { + int i; - dvbdev->entity = kzalloc(sizeof(*dvbdev->entity), GFP_KERNEL); - if (!dvbdev->entity) - return; + for (i = 0; i < dvbdev->tsout_num_entities; i++) { + media_device_unregister_entity(&dvbdev->tsout_entity[i]); + kfree(dvbdev->tsout_entity[i].name); + } + kfree(dvbdev->tsout_entity); + kfree(dvbdev->tsout_pads); + dvbdev->tsout_entity = NULL; + dvbdev->tsout_pads = NULL; - dvbdev->entity->info.dev.major = DVB_MAJOR; - dvbdev->entity->info.dev.minor = minor; - dvbdev->entity->name = dvbdev->name; + dvbdev->tsout_num_entities = 0; + } + + if (dvbdev->intf_devnode) { + media_devnode_remove(dvbdev->intf_devnode); + dvbdev->intf_devnode = NULL; + } + + if (dvbdev->adapter->conn) { + media_device_unregister_entity(dvbdev->adapter->conn); + dvbdev->adapter->conn = NULL; + kfree(dvbdev->adapter->conn_pads); + dvbdev->adapter->conn_pads = NULL; + } +#endif +} + +#if defined(CONFIG_MEDIA_CONTROLLER_DVB) +static int dvb_create_tsout_entity(struct dvb_device *dvbdev, + const char *name, int npads) +{ + int i, ret = 0; + + dvbdev->tsout_pads = kcalloc(npads, sizeof(*dvbdev->tsout_pads), + GFP_KERNEL); + if (!dvbdev->tsout_pads) + return -ENOMEM; + + dvbdev->tsout_entity = kcalloc(npads, sizeof(*dvbdev->tsout_entity), + GFP_KERNEL); + if (!dvbdev->tsout_entity) + return -ENOMEM; + + dvbdev->tsout_num_entities = npads; + + for (i = 0; i < npads; i++) { + struct media_pad *pads = &dvbdev->tsout_pads[i]; + struct media_entity *entity = &dvbdev->tsout_entity[i]; + + entity->name = kasprintf(GFP_KERNEL, "%s #%d", name, i); + if (!entity->name) + return -ENOMEM; + + entity->function = MEDIA_ENT_F_IO_DTV; + pads->flags = MEDIA_PAD_FL_SINK; + + ret = media_entity_pads_init(entity, 1, pads); + if (ret < 0) + return ret; + + ret = media_device_register_entity(dvbdev->adapter->mdev, + entity); + if (ret < 0) + return ret; + } + return 0; +} + +#define DEMUX_TSOUT "demux-tsout" +#define DVR_TSOUT "dvr-tsout" + +static int dvb_create_media_entity(struct dvb_device *dvbdev, + int type, int demux_sink_pads) +{ + int i, ret, npads; switch (type) { - case DVB_DEVICE_CA: - case DVB_DEVICE_DEMUX: case DVB_DEVICE_FRONTEND: npads = 2; break; - case DVB_DEVICE_NET: - npads = 0; + case DVB_DEVICE_DVR: + ret = dvb_create_tsout_entity(dvbdev, DVR_TSOUT, + demux_sink_pads); + return ret; + case DVB_DEVICE_DEMUX: + npads = 1 + demux_sink_pads; + ret = dvb_create_tsout_entity(dvbdev, DEMUX_TSOUT, + demux_sink_pads); + if (ret < 0) + return ret; + break; + case DVB_DEVICE_CA: + npads = 2; break; + case DVB_DEVICE_NET: + /* + * We should be creating entities for the MPE/ULE + * decapsulation hardware (or software implementation). + * + * However, the number of for the MPE/ULE decaps may not be + * fixed. As we don't have yet dynamic support for PADs at + * the Media Controller, let's not create the decap + * entities yet. + */ + return 0; default: - npads = 1; + return 0; } + dvbdev->entity = kzalloc(sizeof(*dvbdev->entity), GFP_KERNEL); + if (!dvbdev->entity) + return -ENOMEM; + + dvbdev->entity->name = dvbdev->name; + if (npads) { dvbdev->pads = kcalloc(npads, sizeof(*dvbdev->pads), GFP_KERNEL); - if (!dvbdev->pads) { - kfree(dvbdev->entity); - return; - } + if (!dvbdev->pads) + return -ENOMEM; } switch (type) { case DVB_DEVICE_FRONTEND: - dvbdev->entity->type = MEDIA_ENT_T_DEVNODE_DVB_FE; + dvbdev->entity->function = MEDIA_ENT_F_DTV_DEMOD; dvbdev->pads[0].flags = MEDIA_PAD_FL_SINK; dvbdev->pads[1].flags = MEDIA_PAD_FL_SOURCE; break; case DVB_DEVICE_DEMUX: - dvbdev->entity->type = MEDIA_ENT_T_DEVNODE_DVB_DEMUX; - dvbdev->pads[0].flags = MEDIA_PAD_FL_SINK; - dvbdev->pads[1].flags = MEDIA_PAD_FL_SOURCE; - break; - case DVB_DEVICE_DVR: - dvbdev->entity->type = MEDIA_ENT_T_DEVNODE_DVB_DVR; + dvbdev->entity->function = MEDIA_ENT_F_TS_DEMUX; dvbdev->pads[0].flags = MEDIA_PAD_FL_SINK; + for (i = 1; i < npads; i++) + dvbdev->pads[i].flags = MEDIA_PAD_FL_SOURCE; break; case DVB_DEVICE_CA: - dvbdev->entity->type = MEDIA_ENT_T_DEVNODE_DVB_CA; + dvbdev->entity->function = MEDIA_ENT_F_DTV_CA; dvbdev->pads[0].flags = MEDIA_PAD_FL_SINK; dvbdev->pads[1].flags = MEDIA_PAD_FL_SOURCE; break; - case DVB_DEVICE_NET: - dvbdev->entity->type = MEDIA_ENT_T_DEVNODE_DVB_NET; - break; default: + /* Should never happen, as the first switch prevents it */ kfree(dvbdev->entity); + kfree(dvbdev->pads); dvbdev->entity = NULL; - return; + dvbdev->pads = NULL; + return 0; } - if (npads) - ret = media_entity_init(dvbdev->entity, npads, dvbdev->pads, 0); - if (!ret) - ret = media_device_register_entity(dvbdev->adapter->mdev, - dvbdev->entity); - if (ret < 0) { - printk(KERN_ERR - "%s: media_device_register_entity failed for %s\n", - __func__, dvbdev->entity->name); - kfree(dvbdev->pads); - kfree(dvbdev->entity); - dvbdev->entity = NULL; - return; + if (npads) { + ret = media_entity_pads_init(dvbdev->entity, npads, dvbdev->pads); + if (ret) + return ret; } + ret = media_device_register_entity(dvbdev->adapter->mdev, + dvbdev->entity); + if (ret) + return (ret); - printk(KERN_DEBUG "%s: media device '%s' registered.\n", + printk(KERN_DEBUG "%s: media entity '%s' registered.\n", __func__, dvbdev->entity->name); + + return 0; +} +#endif + +static int dvb_register_media_device(struct dvb_device *dvbdev, + int type, int minor, + unsigned demux_sink_pads) +{ +#if defined(CONFIG_MEDIA_CONTROLLER_DVB) + struct media_link *link; + u32 intf_type; + int ret; + + if (!dvbdev->adapter->mdev) + return 0; + + ret = dvb_create_media_entity(dvbdev, type, demux_sink_pads); + if (ret) + return ret; + + switch (type) { + case DVB_DEVICE_FRONTEND: + intf_type = MEDIA_INTF_T_DVB_FE; + break; + case DVB_DEVICE_DEMUX: + intf_type = MEDIA_INTF_T_DVB_DEMUX; + break; + case DVB_DEVICE_DVR: + intf_type = MEDIA_INTF_T_DVB_DVR; + break; + case DVB_DEVICE_CA: + intf_type = MEDIA_INTF_T_DVB_CA; + break; + case DVB_DEVICE_NET: + intf_type = MEDIA_INTF_T_DVB_NET; + break; + default: + return 0; + } + + dvbdev->intf_devnode = media_devnode_create(dvbdev->adapter->mdev, + intf_type, 0, + DVB_MAJOR, minor); + + if (!dvbdev->intf_devnode) + return -ENOMEM; + + /* + * Create the "obvious" link, e. g. the ones that represent + * a direct association between an interface and an entity. + * Other links should be created elsewhere, like: + * DVB FE intf -> tuner + * DVB demux intf -> dvr + */ + + if (!dvbdev->entity) + return 0; + + link = media_create_intf_link(dvbdev->entity, &dvbdev->intf_devnode->intf, + MEDIA_LNK_FL_ENABLED); + if (!link) + return -ENOMEM; #endif + return 0; } int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, - const struct dvb_device *template, void *priv, int type) + const struct dvb_device *template, void *priv, int type, + int demux_sink_pads) { struct dvb_device *dvbdev; struct file_operations *dvbdevfops; struct device *clsdev; int minor; - int id; + int id, ret; mutex_lock(&dvbdev_register_lock); @@ -286,7 +442,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, return -ENFILE; } - *pdvbdev = dvbdev = kmalloc(sizeof(struct dvb_device), GFP_KERNEL); + *pdvbdev = dvbdev = kzalloc(sizeof(*dvbdev), GFP_KERNEL); if (!dvbdev){ mutex_unlock(&dvbdev_register_lock); @@ -335,6 +491,20 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, dvb_minors[minor] = dvbdev; up_write(&minor_rwsem); + ret = dvb_register_media_device(dvbdev, type, minor, demux_sink_pads); + if (ret) { + printk(KERN_ERR + "%s: dvb_register_media_device failed to create the mediagraph\n", + __func__); + + dvb_media_device_free(dvbdev); + kfree(dvbdevfops); + kfree(dvbdev); + up_write(&minor_rwsem); + mutex_unlock(&dvbdev_register_lock); + return ret; + } + mutex_unlock(&dvbdev_register_lock); clsdev = device_create(dvb_class, adap->device, @@ -348,8 +518,6 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, dprintk(KERN_DEBUG "DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n", adap->num, dnames[type], id, minor, minor); - dvb_register_media_device(dvbdev, type, minor); - return 0; } EXPORT_SYMBOL(dvb_register_device); @@ -364,15 +532,9 @@ void dvb_unregister_device(struct dvb_device *dvbdev) dvb_minors[dvbdev->minor] = NULL; up_write(&minor_rwsem); - device_destroy(dvb_class, MKDEV(DVB_MAJOR, dvbdev->minor)); + dvb_media_device_free(dvbdev); -#if defined(CONFIG_MEDIA_CONTROLLER_DVB) - if (dvbdev->entity) { - media_device_unregister_entity(dvbdev->entity); - kfree(dvbdev->entity); - kfree(dvbdev->pads); - } -#endif + device_destroy(dvb_class, MKDEV(DVB_MAJOR, dvbdev->minor)); list_del (&dvbdev->list_head); kfree (dvbdev->fops); @@ -382,46 +544,212 @@ EXPORT_SYMBOL(dvb_unregister_device); #ifdef CONFIG_MEDIA_CONTROLLER_DVB -void dvb_create_media_graph(struct dvb_adapter *adap) + +static int dvb_create_io_intf_links(struct dvb_adapter *adap, + struct media_interface *intf, + char *name) +{ + struct media_device *mdev = adap->mdev; + struct media_entity *entity; + struct media_link *link; + + media_device_for_each_entity(entity, mdev) { + if (entity->function == MEDIA_ENT_F_IO_DTV) { + if (strncmp(entity->name, name, strlen(name))) + continue; + link = media_create_intf_link(entity, intf, + MEDIA_LNK_FL_ENABLED); + if (!link) + return -ENOMEM; + } + } + return 0; +} + +int dvb_create_media_graph(struct dvb_adapter *adap, + bool create_rf_connector) { struct media_device *mdev = adap->mdev; - struct media_entity *entity, *tuner = NULL, *fe = NULL; - struct media_entity *demux = NULL, *dvr = NULL, *ca = NULL; + struct media_entity *entity, *tuner = NULL, *demod = NULL, *conn; + struct media_entity *demux = NULL, *ca = NULL; + struct media_link *link; + struct media_interface *intf; + unsigned demux_pad = 0; + unsigned dvr_pad = 0; + unsigned ntuner = 0, ndemod = 0; + int ret; + static const char *connector_name = "Television"; if (!mdev) - return; + return 0; media_device_for_each_entity(entity, mdev) { - switch (entity->type) { - case MEDIA_ENT_T_V4L2_SUBDEV_TUNER: + switch (entity->function) { + case MEDIA_ENT_F_TUNER: tuner = entity; + ntuner++; break; - case MEDIA_ENT_T_DEVNODE_DVB_FE: - fe = entity; + case MEDIA_ENT_F_DTV_DEMOD: + demod = entity; + ndemod++; break; - case MEDIA_ENT_T_DEVNODE_DVB_DEMUX: + case MEDIA_ENT_F_TS_DEMUX: demux = entity; break; - case MEDIA_ENT_T_DEVNODE_DVB_DVR: - dvr = entity; - break; - case MEDIA_ENT_T_DEVNODE_DVB_CA: + case MEDIA_ENT_F_DTV_CA: ca = entity; break; } } - if (tuner && fe) - media_entity_create_link(tuner, 0, fe, 0, 0); + /* + * Prepare to signalize to media_create_pad_links() that multiple + * entities of the same type exists and a 1:n or n:1 links need to be + * created. + * NOTE: if both tuner and demod have multiple instances, it is up + * to the caller driver to create such links. + */ + if (ntuner > 1) + tuner = NULL; + if (ndemod > 1) + demod = NULL; + + if (create_rf_connector) { + conn = kzalloc(sizeof(*conn), GFP_KERNEL); + if (!conn) + return -ENOMEM; + adap->conn = conn; + + adap->conn_pads = kcalloc(1, sizeof(*adap->conn_pads), + GFP_KERNEL); + if (!adap->conn_pads) + return -ENOMEM; + + conn->flags = MEDIA_ENT_FL_CONNECTOR; + conn->function = MEDIA_ENT_F_CONN_RF; + conn->name = connector_name; + adap->conn_pads->flags = MEDIA_PAD_FL_SOURCE; + + ret = media_entity_pads_init(conn, 1, adap->conn_pads); + if (ret) + return ret; + + ret = media_device_register_entity(mdev, conn); + if (ret) + return ret; + + if (!ntuner) + ret = media_create_pad_links(mdev, + MEDIA_ENT_F_CONN_RF, + conn, 0, + MEDIA_ENT_F_DTV_DEMOD, + demod, 0, + MEDIA_LNK_FL_ENABLED, + false); + else + ret = media_create_pad_links(mdev, + MEDIA_ENT_F_CONN_RF, + conn, 0, + MEDIA_ENT_F_TUNER, + tuner, TUNER_PAD_RF_INPUT, + MEDIA_LNK_FL_ENABLED, + false); + if (ret) + return ret; + } + + if (ntuner && ndemod) { + ret = media_create_pad_links(mdev, + MEDIA_ENT_F_TUNER, + tuner, TUNER_PAD_IF_OUTPUT, + MEDIA_ENT_F_DTV_DEMOD, + demod, 0, MEDIA_LNK_FL_ENABLED, + false); + if (ret) + return ret; + } + + if (ndemod && demux) { + ret = media_create_pad_links(mdev, + MEDIA_ENT_F_DTV_DEMOD, + demod, 1, + MEDIA_ENT_F_TS_DEMUX, + demux, 0, MEDIA_LNK_FL_ENABLED, + false); + if (ret) + return -ENOMEM; + } + if (demux && ca) { + ret = media_create_pad_link(demux, 1, ca, + 0, MEDIA_LNK_FL_ENABLED); + if (!ret) + return -ENOMEM; + } - if (fe && demux) - media_entity_create_link(fe, 1, demux, 0, MEDIA_LNK_FL_ENABLED); + /* Create demux links for each ringbuffer/pad */ + if (demux) { + media_device_for_each_entity(entity, mdev) { + if (entity->function == MEDIA_ENT_F_IO_DTV) { + if (!strncmp(entity->name, DVR_TSOUT, + strlen(DVR_TSOUT))) { + ret = media_create_pad_link(demux, + ++dvr_pad, + entity, 0, 0); + if (ret) + return ret; + } + if (!strncmp(entity->name, DEMUX_TSOUT, + strlen(DEMUX_TSOUT))) { + ret = media_create_pad_link(demux, + ++demux_pad, + entity, 0, 0); + if (ret) + return ret; + } + } + } + } - if (demux && dvr) - media_entity_create_link(demux, 1, dvr, 0, MEDIA_LNK_FL_ENABLED); + /* Create interface links for FE->tuner, DVR->demux and CA->ca */ + media_device_for_each_intf(intf, mdev) { + if (intf->type == MEDIA_INTF_T_DVB_CA && ca) { + link = media_create_intf_link(ca, intf, + MEDIA_LNK_FL_ENABLED); + if (!link) + return -ENOMEM; + } - if (demux && ca) - media_entity_create_link(demux, 1, ca, 0, MEDIA_LNK_FL_ENABLED); + if (intf->type == MEDIA_INTF_T_DVB_FE && tuner) { + link = media_create_intf_link(tuner, intf, + MEDIA_LNK_FL_ENABLED); + if (!link) + return -ENOMEM; + } +#if 0 + /* + * Indirect link - let's not create yet, as we don't know how + * to handle indirect links, nor if this will + * actually be needed. + */ + if (intf->type == MEDIA_INTF_T_DVB_DVR && demux) { + link = media_create_intf_link(demux, intf, + MEDIA_LNK_FL_ENABLED); + if (!link) + return -ENOMEM; + } +#endif + if (intf->type == MEDIA_INTF_T_DVB_DVR) { + ret = dvb_create_io_intf_links(adap, intf, DVR_TSOUT); + if (ret) + return ret; + } + if (intf->type == MEDIA_INTF_T_DVB_DEMUX) { + ret = dvb_create_io_intf_links(adap, intf, DEMUX_TSOUT); + if (ret) + return ret; + } + } + return 0; } EXPORT_SYMBOL_GPL(dvb_create_media_graph); #endif diff --git a/drivers/media/dvb-core/dvbdev.h b/drivers/media/dvb-core/dvbdev.h index 1069a776b..4aff7bd3d 100644 --- a/drivers/media/dvb-core/dvbdev.h +++ b/drivers/media/dvb-core/dvbdev.h @@ -75,6 +75,9 @@ struct dvb_frontend; * used. * @mdev: pointer to struct media_device, used when the media * controller is used. + * @conn: RF connector. Used only if the device has no separate + * tuner. + * @conn_pads: pointer to struct media_pad associated with @conn; */ struct dvb_adapter { int num; @@ -94,6 +97,8 @@ struct dvb_adapter { #if defined(CONFIG_MEDIA_CONTROLLER_DVB) struct media_device *mdev; + struct media_entity *conn; + struct media_pad *conn_pads; #endif }; @@ -120,6 +125,11 @@ struct dvb_adapter { * @entity: pointer to struct media_entity associated with the device node * @pads: pointer to struct media_pad associated with @entity; * @priv: private data + * @intf_devnode: Pointer to media_intf_devnode. Used by the dvbdev core to + * store the MC device node interface + * @tsout_num_entities: Number of Transport Stream output entities + * @tsout_entity: array with MC entities associated to each TS output node + * @tsout_pads: array with the source pads for each @tsout_entity * * This structure is used by the DVB core (frontend, CA, net, demux) in * order to create the device nodes. Usually, driver should not initialize @@ -148,8 +158,11 @@ struct dvb_device { const char *name; /* Allocated and filled inside dvbdev.c */ - struct media_entity *entity; - struct media_pad *pads; + struct media_intf_devnode *intf_devnode; + + unsigned tsout_num_entities; + struct media_entity *entity, *tsout_entity; + struct media_pad *pads, *tsout_pads; #endif void *priv; @@ -185,14 +198,18 @@ int dvb_unregister_adapter(struct dvb_adapter *adap); * stored * @template: Template used to create &pdvbdev; * @priv: private data - * @type: type of the device: DVB_DEVICE_SEC, DVB_DEVICE_FRONTEND, - * DVB_DEVICE_DEMUX, DVB_DEVICE_DVR, DVB_DEVICE_CA, DVB_DEVICE_NET + * @type: type of the device: %DVB_DEVICE_SEC, %DVB_DEVICE_FRONTEND, + * %DVB_DEVICE_DEMUX, %DVB_DEVICE_DVR, %DVB_DEVICE_CA, + * %DVB_DEVICE_NET + * @demux_sink_pads: Number of demux outputs, to be used to create the TS + * outputs via the Media Controller. */ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, const struct dvb_device *template, void *priv, - int type); + int type, + int demux_sink_pads); /** * dvb_unregister_device - Unregisters a DVB device @@ -202,16 +219,43 @@ int dvb_register_device(struct dvb_adapter *adap, void dvb_unregister_device(struct dvb_device *dvbdev); #ifdef CONFIG_MEDIA_CONTROLLER_DVB -void dvb_create_media_graph(struct dvb_adapter *adap); +/** + * dvb_create_media_graph - Creates media graph for the Digital TV part of the + * device. + * + * @adap: pointer to struct dvb_adapter + * @create_rf_connector: if true, it creates the RF connector too + * + * This function checks all DVB-related functions at the media controller + * entities and creates the needed links for the media graph. It is + * capable of working with multiple tuners or multiple frontends, but it + * won't create links if the device has multiple tuners and multiple frontends + * or if the device has multiple muxes. In such case, the caller driver should + * manually create the remaining links. + */ +__must_check int dvb_create_media_graph(struct dvb_adapter *adap, + bool create_rf_connector); + static inline void dvb_register_media_controller(struct dvb_adapter *adap, struct media_device *mdev) { adap->mdev = mdev; } +static inline struct media_device +*dvb_get_media_controller(struct dvb_adapter *adap) +{ + return adap->mdev; +} #else -static inline void dvb_create_media_graph(struct dvb_adapter *adap) {} +static inline +int dvb_create_media_graph(struct dvb_adapter *adap, + bool create_rf_connector) +{ + return 0; +}; #define dvb_register_media_controller(a, b) {} +#define dvb_get_media_controller(a) NULL #endif int dvb_generic_open (struct inode *inode, struct file *file); diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index 292c9479b..310e4b8be 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig @@ -264,7 +264,7 @@ config DVB_MB86A16 config DVB_TDA10071 tristate "NXP TDA10071" depends on DVB_CORE && I2C - select REGMAP + select REGMAP_I2C default m if !MEDIA_SUBDRV_AUTOSELECT help Say Y when you want to support this frontend. diff --git a/drivers/media/dvb-frontends/au8522_common.c b/drivers/media/dvb-frontends/au8522_common.c index 3559ff230..f135126bc 100644 --- a/drivers/media/dvb-frontends/au8522_common.c +++ b/drivers/media/dvb-frontends/au8522_common.c @@ -44,7 +44,7 @@ int au8522_writereg(struct au8522_state *state, u16 reg, u8 data) int ret; u8 buf[] = { (reg >> 8) | 0x80, reg & 0xff, data }; - struct i2c_msg msg = { .addr = state->config->demod_address, + struct i2c_msg msg = { .addr = state->config.demod_address, .flags = 0, .buf = buf, .len = 3 }; ret = i2c_transfer(state->i2c, &msg, 1); @@ -64,9 +64,9 @@ u8 au8522_readreg(struct au8522_state *state, u16 reg) u8 b1[] = { 0 }; struct i2c_msg msg[] = { - { .addr = state->config->demod_address, .flags = 0, + { .addr = state->config.demod_address, .flags = 0, .buf = b0, .len = 2 }, - { .addr = state->config->demod_address, .flags = I2C_M_RD, + { .addr = state->config.demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; ret = i2c_transfer(state->i2c, msg, 2); @@ -140,7 +140,7 @@ EXPORT_SYMBOL(au8522_release_state); static int au8522_led_gpio_enable(struct au8522_state *state, int onoff) { - struct au8522_led_config *led_config = state->config->led_cfg; + struct au8522_led_config *led_config = state->config.led_cfg; u8 val; /* bail out if we can't control an LED */ @@ -170,7 +170,7 @@ static int au8522_led_gpio_enable(struct au8522_state *state, int onoff) */ int au8522_led_ctrl(struct au8522_state *state, int led) { - struct au8522_led_config *led_config = state->config->led_cfg; + struct au8522_led_config *led_config = state->config.led_cfg; int i, ret = 0; /* bail out if we can't control an LED */ diff --git a/drivers/media/dvb-frontends/au8522_decoder.c b/drivers/media/dvb-frontends/au8522_decoder.c index 28d7dc2fe..73612c535 100644 --- a/drivers/media/dvb-frontends/au8522_decoder.c +++ b/drivers/media/dvb-frontends/au8522_decoder.c @@ -730,7 +730,9 @@ static int au8522_probe(struct i2c_client *client, struct v4l2_ctrl_handler *hdl; struct v4l2_subdev *sd; int instance; - struct au8522_config *demod_config; +#ifdef CONFIG_MEDIA_CONTROLLER + int ret; +#endif /* Check if the adapter supports the needed features */ if (!i2c_check_functionality(client->adapter, @@ -754,19 +756,25 @@ static int au8522_probe(struct i2c_client *client, break; } - demod_config = kzalloc(sizeof(struct au8522_config), GFP_KERNEL); - if (demod_config == NULL) { - if (instance == 1) - kfree(state); - return -ENOMEM; - } - demod_config->demod_address = 0x8e >> 1; - - state->config = demod_config; + state->config.demod_address = 0x8e >> 1; state->i2c = client->adapter; sd = &state->sd; v4l2_i2c_subdev_init(sd, client, &au8522_ops); +#if defined(CONFIG_MEDIA_CONTROLLER) + + state->pads[AU8522_PAD_INPUT].flags = MEDIA_PAD_FL_SINK; + state->pads[AU8522_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE; + state->pads[AU8522_PAD_VBI_OUT].flags = MEDIA_PAD_FL_SOURCE; + sd->entity.function = MEDIA_ENT_F_ATV_DECODER; + + ret = media_entity_pads_init(&sd->entity, ARRAY_SIZE(state->pads), + state->pads); + if (ret < 0) { + v4l_info(client, "failed to initialize media entity!\n"); + return ret; + } +#endif hdl = &state->hdl; v4l2_ctrl_handler_init(hdl, 4); @@ -784,8 +792,7 @@ static int au8522_probe(struct i2c_client *client, int err = hdl->error; v4l2_ctrl_handler_free(hdl); - kfree(demod_config); - kfree(state); + au8522_release_state(state); return err; } diff --git a/drivers/media/dvb-frontends/au8522_dig.c b/drivers/media/dvb-frontends/au8522_dig.c index f956f13fb..6c1e97640 100644 --- a/drivers/media/dvb-frontends/au8522_dig.c +++ b/drivers/media/dvb-frontends/au8522_dig.c @@ -566,7 +566,7 @@ static int au8522_enable_modulation(struct dvb_frontend *fe, au8522_writereg(state, VSB_mod_tab[i].reg, VSB_mod_tab[i].data); - au8522_set_if(fe, state->config->vsb_if); + au8522_set_if(fe, state->config.vsb_if); break; case QAM_64: dprintk("%s() QAM 64\n", __func__); @@ -574,7 +574,7 @@ static int au8522_enable_modulation(struct dvb_frontend *fe, au8522_writereg(state, QAM64_mod_tab[i].reg, QAM64_mod_tab[i].data); - au8522_set_if(fe, state->config->qam_if); + au8522_set_if(fe, state->config.qam_if); break; case QAM_256: if (zv_mode) { @@ -583,7 +583,7 @@ static int au8522_enable_modulation(struct dvb_frontend *fe, au8522_writereg(state, QAM256_mod_tab_zv_mode[i].reg, QAM256_mod_tab_zv_mode[i].data); - au8522_set_if(fe, state->config->qam_if); + au8522_set_if(fe, state->config.qam_if); msleep(100); au8522_writereg(state, 0x821a, 0x00); } else { @@ -592,7 +592,7 @@ static int au8522_enable_modulation(struct dvb_frontend *fe, au8522_writereg(state, QAM256_mod_tab[i].reg, QAM256_mod_tab[i].data); - au8522_set_if(fe, state->config->qam_if); + au8522_set_if(fe, state->config.qam_if); } break; default: @@ -666,7 +666,7 @@ static int au8522_read_status(struct dvb_frontend *fe, enum fe_status *status) *status |= FE_HAS_LOCK | FE_HAS_SYNC; } - switch (state->config->status_mode) { + switch (state->config.status_mode) { case AU8522_DEMODLOCKING: dprintk("%s() DEMODLOCKING\n", __func__); if (*status & FE_HAS_VITERBI) @@ -704,7 +704,7 @@ static int au8522_read_status(struct dvb_frontend *fe, enum fe_status *status) static int au8522_led_status(struct au8522_state *state, const u16 *snr) { - struct au8522_led_config *led_config = state->config->led_cfg; + struct au8522_led_config *led_config = state->config.led_cfg; int led; u16 strong; @@ -758,7 +758,7 @@ static int au8522_read_snr(struct dvb_frontend *fe, u16 *snr) au8522_readreg(state, 0x4311), snr); - if (state->config->led_cfg) + if (state->config.led_cfg) au8522_led_status(state, snr); return ret; @@ -866,7 +866,7 @@ struct dvb_frontend *au8522_attach(const struct au8522_config *config, } /* setup the state */ - state->config = config; + state->config = *config; state->i2c = i2c; state->operational_mode = AU8522_DIGITAL_MODE; diff --git a/drivers/media/dvb-frontends/au8522_priv.h b/drivers/media/dvb-frontends/au8522_priv.h index 951b3847e..404a0cb0e 100644 --- a/drivers/media/dvb-frontends/au8522_priv.h +++ b/drivers/media/dvb-frontends/au8522_priv.h @@ -39,6 +39,14 @@ #define AU8522_DIGITAL_MODE 1 #define AU8522_SUSPEND_MODE 2 +enum au8522_media_pads { + AU8522_PAD_INPUT, + AU8522_PAD_VID_OUT, + AU8522_PAD_VBI_OUT, + + AU8522_NUM_PADS +}; + struct au8522_state { struct i2c_client *c; struct i2c_adapter *i2c; @@ -50,7 +58,7 @@ struct au8522_state { struct list_head hybrid_tuner_instance_list; /* configuration settings */ - const struct au8522_config *config; + struct au8522_config config; struct dvb_frontend frontend; @@ -68,6 +76,10 @@ struct au8522_state { u32 id; u32 rev; struct v4l2_ctrl_handler hdl; + +#ifdef CONFIG_MEDIA_CONTROLLER + struct media_pad pads[AU8522_NUM_PADS]; +#endif }; /* These are routines shared by both the VSB/QAM demodulator and the analog diff --git a/drivers/media/dvb-frontends/bsbe1-d01a.h b/drivers/media/dvb-frontends/bsbe1-d01a.h index 7ed3c4241..baaf89e76 100644 --- a/drivers/media/dvb-frontends/bsbe1-d01a.h +++ b/drivers/media/dvb-frontends/bsbe1-d01a.h @@ -21,7 +21,7 @@ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * * - * the project's page is at http://www.linuxtv.org + * the project's page is at https://linuxtv.org */ #ifndef BSBE1_D01A_H diff --git a/drivers/media/dvb-frontends/bsbe1.h b/drivers/media/dvb-frontends/bsbe1.h index 53e4d0dbb..4ad766154 100644 --- a/drivers/media/dvb-frontends/bsbe1.h +++ b/drivers/media/dvb-frontends/bsbe1.h @@ -19,7 +19,7 @@ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * * - * the project's page is at http://www.linuxtv.org + * the project's page is at https://linuxtv.org */ #ifndef BSBE1_H diff --git a/drivers/media/dvb-frontends/bsru6.h b/drivers/media/dvb-frontends/bsru6.h index c2a578e13..275c17825 100644 --- a/drivers/media/dvb-frontends/bsru6.h +++ b/drivers/media/dvb-frontends/bsru6.h @@ -19,7 +19,7 @@ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * * - * the project's page is at http://www.linuxtv.org + * the project's page is at https://linuxtv.org */ #ifndef BSRU6_H diff --git a/drivers/media/dvb-frontends/cxd2820r_core.c b/drivers/media/dvb-frontends/cxd2820r_core.c index def6d21d1..24a457d9d 100644 --- a/drivers/media/dvb-frontends/cxd2820r_core.c +++ b/drivers/media/dvb-frontends/cxd2820r_core.c @@ -722,7 +722,7 @@ struct dvb_frontend *cxd2820r_attach(const struct cxd2820r_config *cfg, #ifdef CONFIG_GPIOLIB /* add GPIOs */ priv->gpio_chip.label = KBUILD_MODNAME; - priv->gpio_chip.dev = &priv->i2c->dev; + priv->gpio_chip.parent = &priv->i2c->dev; priv->gpio_chip.owner = THIS_MODULE; priv->gpio_chip.direction_output = cxd2820r_gpio_direction_output; diff --git a/drivers/media/dvb-frontends/isl6405.c b/drivers/media/dvb-frontends/isl6405.c index b46450a10..6913cd687 100644 --- a/drivers/media/dvb-frontends/isl6405.c +++ b/drivers/media/dvb-frontends/isl6405.c @@ -22,7 +22,7 @@ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * * - * the project's page is at http://www.linuxtv.org + * the project's page is at https://linuxtv.org */ #include <linux/delay.h> #include <linux/errno.h> diff --git a/drivers/media/dvb-frontends/isl6405.h b/drivers/media/dvb-frontends/isl6405.h index 3c148b830..4a23d3bdf 100644 --- a/drivers/media/dvb-frontends/isl6405.h +++ b/drivers/media/dvb-frontends/isl6405.h @@ -22,7 +22,7 @@ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * * - * the project's page is at http://www.linuxtv.org + * the project's page is at https://linuxtv.org */ #ifndef _ISL6405_H diff --git a/drivers/media/dvb-frontends/isl6421.c b/drivers/media/dvb-frontends/isl6421.c index 3a4d4606a..0b6d3837d 100644 --- a/drivers/media/dvb-frontends/isl6421.c +++ b/drivers/media/dvb-frontends/isl6421.c @@ -22,7 +22,7 @@ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * * - * the project's page is at http://www.linuxtv.org + * the project's page is at https://linuxtv.org */ #include <linux/delay.h> #include <linux/errno.h> diff --git a/drivers/media/dvb-frontends/isl6421.h b/drivers/media/dvb-frontends/isl6421.h index 327359783..00f9874ca 100644 --- a/drivers/media/dvb-frontends/isl6421.h +++ b/drivers/media/dvb-frontends/isl6421.h @@ -22,7 +22,7 @@ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * * - * the project's page is at http://www.linuxtv.org + * the project's page is at https://linuxtv.org */ #ifndef _ISL6421_H diff --git a/drivers/media/dvb-frontends/lnbp21.c b/drivers/media/dvb-frontends/lnbp21.c index 4aca0fb9a..6261460d9 100644 --- a/drivers/media/dvb-frontends/lnbp21.c +++ b/drivers/media/dvb-frontends/lnbp21.c @@ -22,7 +22,7 @@ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * * - * the project's page is at http://www.linuxtv.org + * the project's page is at https://linuxtv.org */ #include <linux/delay.h> #include <linux/errno.h> diff --git a/drivers/media/dvb-frontends/lnbp21.h b/drivers/media/dvb-frontends/lnbp21.h index a9b530de6..cd9101f6e 100644 --- a/drivers/media/dvb-frontends/lnbp21.h +++ b/drivers/media/dvb-frontends/lnbp21.h @@ -21,7 +21,7 @@ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * * - * the project's page is at http://www.linuxtv.org + * the project's page is at https://linuxtv.org */ #ifndef _LNBP21_H diff --git a/drivers/media/dvb-frontends/lnbp22.c b/drivers/media/dvb-frontends/lnbp22.c index d7ca0fdd0..5c5fd04fd 100644 --- a/drivers/media/dvb-frontends/lnbp22.c +++ b/drivers/media/dvb-frontends/lnbp22.c @@ -22,7 +22,7 @@ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * * - * the project's page is at http://www.linuxtv.org + * the project's page is at https://linuxtv.org */ #include <linux/delay.h> #include <linux/errno.h> diff --git a/drivers/media/dvb-frontends/lnbp22.h b/drivers/media/dvb-frontends/lnbp22.h index 628148385..5d01d9281 100644 --- a/drivers/media/dvb-frontends/lnbp22.h +++ b/drivers/media/dvb-frontends/lnbp22.h @@ -22,7 +22,7 @@ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * * - * the project's page is at http://www.linuxtv.org + * the project's page is at https://linuxtv.org */ #ifndef _LNBP22_H diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c index 4f118c8c7..151c3a6d4 100644 --- a/drivers/media/dvb-frontends/m88ds3103.c +++ b/drivers/media/dvb-frontends/m88ds3103.c @@ -685,7 +685,7 @@ static int m88ds3103_init(struct dvb_frontend *fe) /* request the firmware, this will block and timeout */ ret = reject_firmware(&fw, fw_file, &client->dev); if (ret) { - dev_err(&client->dev, "firmare file '%s' not found\n", fw_file); + dev_err(&client->dev, "firmware file '%s' not found\n", fw_file); goto err; } diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c index 78b87b260..10f211993 100644 --- a/drivers/media/dvb-frontends/rtl2832.c +++ b/drivers/media/dvb-frontends/rtl2832.c @@ -976,7 +976,8 @@ static int rtl2832_regmap_read(void *context, const void *reg_buf, ret = __i2c_transfer(client->adapter, msg, 2); if (ret != 2) { - dev_warn(&client->dev, "i2c reg read failed %d\n", ret); + dev_warn(&client->dev, "i2c reg read failed %d reg %02x\n", + ret, *(u8 *)reg_buf); if (ret >= 0) ret = -EREMOTEIO; return ret; @@ -999,7 +1000,8 @@ static int rtl2832_regmap_write(void *context, const void *data, size_t count) ret = __i2c_transfer(client->adapter, msg, 1); if (ret != 1) { - dev_warn(&client->dev, "i2c reg write failed %d\n", ret); + dev_warn(&client->dev, "i2c reg write failed %d reg %02x\n", + ret, *(u8 *)data); if (ret >= 0) ret = -EREMOTEIO; return ret; @@ -1028,7 +1030,8 @@ static int rtl2832_regmap_gather_write(void *context, const void *reg, ret = __i2c_transfer(client->adapter, msg, 1); if (ret != 1) { - dev_warn(&client->dev, "i2c reg write failed %d\n", ret); + dev_warn(&client->dev, "i2c reg write failed %d reg %02x\n", + ret, *(u8 const *)reg); if (ret >= 0) ret = -EREMOTEIO; return ret; @@ -1097,18 +1100,6 @@ static int rtl2832_enable_slave_ts(struct i2c_client *client) if (ret) goto err; - ret = rtl2832_bulk_write(client, 0x022, "\x01", 1); - if (ret) - goto err; - - ret = rtl2832_bulk_write(client, 0x026, "\x1f", 1); - if (ret) - goto err; - - ret = rtl2832_bulk_write(client, 0x027, "\xff", 1); - if (ret) - goto err; - ret = rtl2832_bulk_write(client, 0x192, "\x7f\xf7\xff", 3); if (ret) goto err; diff --git a/drivers/media/dvb-frontends/rtl2832_sdr.c b/drivers/media/dvb-frontends/rtl2832_sdr.c index dcd8d94c1..b860f02a4 100644 --- a/drivers/media/dvb-frontends/rtl2832_sdr.c +++ b/drivers/media/dvb-frontends/rtl2832_sdr.c @@ -310,7 +310,7 @@ static void rtl2832_sdr_urb_complete(struct urb *urb) len = rtl2832_sdr_convert_stream(dev, ptr, urb->transfer_buffer, urb->actual_length); vb2_set_plane_payload(&fbuf->vb.vb2_buf, 0, len); - v4l2_get_timestamp(&fbuf->vb.timestamp); + fbuf->vb.vb2_buf.timestamp = ktime_get_ns(); fbuf->vb.sequence = dev->sequence++; vb2_buffer_done(&fbuf->vb.vb2_buf, VB2_BUF_STATE_DONE); } @@ -490,7 +490,7 @@ static int rtl2832_sdr_querycap(struct file *file, void *fh, /* Videobuf2 operations */ static int rtl2832_sdr_queue_setup(struct vb2_queue *vq, - const void *parg, unsigned int *nbuffers, + unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) { struct rtl2832_sdr_dev *dev = vb2_get_drv_priv(vq); diff --git a/drivers/media/dvb-frontends/si2165.c b/drivers/media/dvb-frontends/si2165.c index 062063bf5..0111faf7f 100644 --- a/drivers/media/dvb-frontends/si2165.c +++ b/drivers/media/dvb-frontends/si2165.c @@ -1,21 +1,21 @@ /* - Driver for Silicon Labs Si2161 DVB-T and Si2165 DVB-C/-T Demodulator - - Copyright (C) 2013-2014 Matthias Schwarzott <zzam@gentoo.org> - - 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 - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - References: - http://www.silabs.com/Support%20Documents/TechnicalDocs/Si2165-short.pdf -*/ + * Driver for Silicon Labs Si2161 DVB-T and Si2165 DVB-C/-T Demodulator + * + * Copyright (C) 2013-2014 Matthias Schwarzott <zzam@gentoo.org> + * + * 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 + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * References: + * http://www.silabs.com/Support%20Documents/TechnicalDocs/Si2165-short.pdf + */ #include <linux/delay.h> #include <linux/errno.h> @@ -31,16 +31,18 @@ #include "si2165_priv.h" #include "si2165.h" -/* Hauppauge WinTV-HVR-930C-HD B130 / PCTV QuatroStick 521e 1113xx - * uses 16 MHz xtal */ - -/* Hauppauge WinTV-HVR-930C-HD B131 / PCTV QuatroStick 522e 1114xx - * uses 24 MHz clock provided by tuner */ +/* + * Hauppauge WinTV-HVR-930C-HD B130 / PCTV QuatroStick 521e 1113xx + * uses 16 MHz xtal + * + * Hauppauge WinTV-HVR-930C-HD B131 / PCTV QuatroStick 522e 1114xx + * uses 24 MHz clock provided by tuner + */ struct si2165_state { struct i2c_adapter *i2c; - struct dvb_frontend frontend; + struct dvb_frontend fe; struct si2165_config config; @@ -241,6 +243,27 @@ err: return ret; } +#define REG16(reg, val) { (reg), (val) & 0xff }, { (reg)+1, (val)>>8 & 0xff } +struct si2165_reg_value_pair { + u16 reg; + u8 val; +}; + +static int si2165_write_reg_list(struct si2165_state *state, + const struct si2165_reg_value_pair *regs, + int count) +{ + int i; + int ret; + + for (i = 0; i < count; i++) { + ret = si2165_writereg8(state, regs[i].reg, regs[i].val); + if (ret < 0) + return ret; + } + return 0; +} + static int si2165_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *s) { @@ -258,8 +281,10 @@ static int si2165_init_pll(struct si2165_state *state) u8 divl = 12; u8 buf[4]; - /* hardcoded values can be deleted if calculation is verified - * or it yields the same values as the windows driver */ + /* + * hardcoded values can be deleted if calculation is verified + * or it yields the same values as the windows driver + */ switch (ref_freq_Hz) { case 16000000u: divn = 56; @@ -274,8 +299,10 @@ static int si2165_init_pll(struct si2165_state *state) if (ref_freq_Hz > 16000000u) divr = 2; - /* now select divn and divp such that - * fvco is in 1624..1824 MHz */ + /* + * now select divn and divp such that + * fvco is in 1624..1824 MHz + */ if (1624000000u * divr > ref_freq_Hz * 2u * 63u) divp = 4; @@ -341,10 +368,12 @@ static int si2165_upload_firmware_block(struct si2165_state *state, if (len % 4 != 0) return -EINVAL; - deb_fw_load("si2165_upload_firmware_block called with len=0x%x offset=0x%x blockcount=0x%x\n", + deb_fw_load( + "si2165_upload_firmware_block called with len=0x%x offset=0x%x blockcount=0x%x\n", len, offset, block_count); while (offset+12 <= len && cur_block < block_count) { - deb_fw_load("si2165_upload_firmware_block in while len=0x%x offset=0x%x cur_block=0x%x blockcount=0x%x\n", + deb_fw_load( + "si2165_upload_firmware_block in while len=0x%x offset=0x%x cur_block=0x%x blockcount=0x%x\n", len, offset, cur_block, block_count); wordcount = data[offset]; if (wordcount < 1 || data[offset+1] || @@ -383,7 +412,8 @@ static int si2165_upload_firmware_block(struct si2165_state *state, cur_block++; } - deb_fw_load("si2165_upload_firmware_block after while len=0x%x offset=0x%x cur_block=0x%x blockcount=0x%x\n", + deb_fw_load( + "si2165_upload_firmware_block after while len=0x%x offset=0x%x cur_block=0x%x blockcount=0x%x\n", len, offset, cur_block, block_count); if (poffset) @@ -511,7 +541,7 @@ static int si2165_upload_firmware(struct si2165_state *state) &offset, block_count); if (ret < 0) { dev_err(&state->i2c->dev, - "%s: firmare could not be uploaded\n", + "%s: firmware could not be uploaded\n", KBUILD_MODNAME); goto error; } @@ -535,7 +565,7 @@ static int si2165_upload_firmware(struct si2165_state *state) if (len != offset) { dev_err(&state->i2c->dev, - "%s: firmare len mismatch %04x != %04x\n", + "%s: firmware len mismatch %04x != %04x\n", KBUILD_MODNAME, len, offset); ret = -EINVAL; goto error; @@ -633,7 +663,7 @@ static int si2165_init(struct dvb_frontend *fe) goto error; /* ber_pkt */ - ret = si2165_writereg16(state, 0x0470 , 0x7530); + ret = si2165_writereg16(state, 0x0470, 0x7530); if (ret < 0) goto error; @@ -660,22 +690,19 @@ static int si2165_init(struct dvb_frontend *fe) goto error; } - /* write adc values after each reset*/ - ret = si2165_writereg8(state, 0x012a, 0x46); - if (ret < 0) - goto error; - ret = si2165_writereg8(state, 0x012c, 0x00); + /* ts output config */ + ret = si2165_writereg8(state, 0x04e4, 0x20); if (ret < 0) - goto error; - ret = si2165_writereg8(state, 0x012e, 0x0a); + return ret; + ret = si2165_writereg16(state, 0x04ef, 0x00fe); if (ret < 0) - goto error; - ret = si2165_writereg8(state, 0x012f, 0xff); + return ret; + ret = si2165_writereg24(state, 0x04f4, 0x555555); if (ret < 0) - goto error; - ret = si2165_writereg8(state, 0x0123, 0x70); + return ret; + ret = si2165_writereg8(state, 0x04e5, 0x01); if (ret < 0) - goto error; + return ret; return 0; error: @@ -733,16 +760,26 @@ static int si2165_set_oversamp(struct si2165_state *state, u32 dvb_rate) do_div(oversamp, dvb_rate); reg_value = oversamp & 0x3fffffff; - /* oversamp, usbdump contained 0x03100000; */ + dprintk("%s: Write oversamp=%#x\n", __func__, reg_value); return si2165_writereg32(state, 0x00e4, reg_value); } -static int si2165_set_if_freq_shift(struct si2165_state *state, u32 IF) +static int si2165_set_if_freq_shift(struct si2165_state *state) { + struct dvb_frontend *fe = &state->fe; u64 if_freq_shift; s32 reg_value = 0; u32 fe_clk = si2165_get_fe_clk(state); + u32 IF = 0; + if (!fe->ops.tuner_ops.get_if_frequency) { + dev_err(&state->i2c->dev, + "%s: Error: get_if_frequency() not defined at tuner. Can't work without it!\n", + KBUILD_MODNAME); + return -EINVAL; + } + + fe->ops.tuner_ops.get_if_frequency(fe, &IF); if_freq_shift = IF; if_freq_shift <<= 29; @@ -758,25 +795,39 @@ static int si2165_set_if_freq_shift(struct si2165_state *state, u32 IF) return si2165_writereg32(state, 0x00e8, reg_value); } -static int si2165_set_parameters(struct dvb_frontend *fe) +static const struct si2165_reg_value_pair dvbt_regs[] = { + /* standard = DVB-T */ + { 0x00ec, 0x01 }, + { 0x08f8, 0x00 }, + /* impulsive_noise_remover */ + { 0x031c, 0x01 }, + { 0x00cb, 0x00 }, + /* agc2 */ + { 0x016e, 0x41 }, + { 0x016c, 0x0e }, + { 0x016d, 0x10 }, + /* agc */ + { 0x015b, 0x03 }, + { 0x0150, 0x78 }, + /* agc */ + { 0x01a0, 0x78 }, + { 0x01c8, 0x68 }, + /* freq_sync_range */ + REG16(0x030c, 0x0064), + /* gp_reg0 */ + { 0x0387, 0x00 } +}; + +static int si2165_set_frontend_dvbt(struct dvb_frontend *fe) { int ret; struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct si2165_state *state = fe->demodulator_priv; - u8 val[3]; - u32 IF; u32 dvb_rate = 0; u16 bw10k; dprintk("%s: called\n", __func__); - if (!fe->ops.tuner_ops.get_if_frequency) { - dev_err(&state->i2c->dev, - "%s: Error: get_if_frequency() not defined at tuner. Can't work without it!\n", - KBUILD_MODNAME); - return -EINVAL; - } - if (!state->has_dvbt) return -EINVAL; @@ -788,34 +839,10 @@ static int si2165_set_parameters(struct dvb_frontend *fe) bw10k = 800; } - /* standard = DVB-T */ - ret = si2165_writereg8(state, 0x00ec, 0x01); - if (ret < 0) - return ret; ret = si2165_adjust_pll_divl(state, 12); if (ret < 0) return ret; - fe->ops.tuner_ops.get_if_frequency(fe, &IF); - ret = si2165_set_if_freq_shift(state, IF); - if (ret < 0) - return ret; - ret = si2165_writereg8(state, 0x08f8, 0x00); - if (ret < 0) - return ret; - /* ts output config */ - ret = si2165_writereg8(state, 0x04e4, 0x20); - if (ret < 0) - return ret; - ret = si2165_writereg16(state, 0x04ef, 0x00fe); - if (ret < 0) - return ret; - ret = si2165_writereg24(state, 0x04f4, 0x555555); - if (ret < 0) - return ret; - ret = si2165_writereg8(state, 0x04e5, 0x01); - if (ret < 0) - return ret; /* bandwidth in 10KHz steps */ ret = si2165_writereg16(state, 0x0308, bw10k); if (ret < 0) @@ -823,48 +850,115 @@ static int si2165_set_parameters(struct dvb_frontend *fe) ret = si2165_set_oversamp(state, dvb_rate); if (ret < 0) return ret; - /* impulsive_noise_remover */ - ret = si2165_writereg8(state, 0x031c, 0x01); - if (ret < 0) - return ret; - ret = si2165_writereg8(state, 0x00cb, 0x00); + + ret = si2165_write_reg_list(state, dvbt_regs, ARRAY_SIZE(dvbt_regs)); if (ret < 0) return ret; + + return 0; +} + +static const struct si2165_reg_value_pair dvbc_regs[] = { + /* standard = DVB-C */ + { 0x00ec, 0x05 }, + { 0x08f8, 0x00 }, + /* agc2 */ - ret = si2165_writereg8(state, 0x016e, 0x41); - if (ret < 0) - return ret; - ret = si2165_writereg8(state, 0x016c, 0x0e); - if (ret < 0) - return ret; - ret = si2165_writereg8(state, 0x016d, 0x10); - if (ret < 0) - return ret; + { 0x016e, 0x50 }, + { 0x016c, 0x0e }, + { 0x016d, 0x10 }, /* agc */ - ret = si2165_writereg8(state, 0x015b, 0x03); - if (ret < 0) - return ret; - ret = si2165_writereg8(state, 0x0150, 0x78); - if (ret < 0) - return ret; + { 0x015b, 0x03 }, + { 0x0150, 0x68 }, /* agc */ - ret = si2165_writereg8(state, 0x01a0, 0x78); + { 0x01a0, 0x68 }, + { 0x01c8, 0x50 }, + + { 0x0278, 0x0d }, + + { 0x023a, 0x05 }, + { 0x0261, 0x09 }, + REG16(0x0350, 0x3e80), + { 0x02f4, 0x00 }, + + { 0x00cb, 0x01 }, + REG16(0x024c, 0x0000), + REG16(0x027c, 0x0000), + { 0x0232, 0x03 }, + { 0x02f4, 0x0b }, + { 0x018b, 0x00 }, +}; + +static int si2165_set_frontend_dvbc(struct dvb_frontend *fe) +{ + struct si2165_state *state = fe->demodulator_priv; + int ret; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + const u32 dvb_rate = p->symbol_rate; + const u32 bw_hz = p->bandwidth_hz; + + if (!state->has_dvbc) + return -EINVAL; + + if (dvb_rate == 0) + return -EINVAL; + + ret = si2165_adjust_pll_divl(state, 14); if (ret < 0) return ret; - ret = si2165_writereg8(state, 0x01c8, 0x68); + + /* Oversampling */ + ret = si2165_set_oversamp(state, dvb_rate); if (ret < 0) return ret; - /* freq_sync_range */ - ret = si2165_writereg16(state, 0x030c, 0x0064); + + ret = si2165_writereg32(state, 0x00c4, bw_hz); if (ret < 0) return ret; - /* gp_reg0 */ - ret = si2165_readreg8(state, 0x0387, val); + + ret = si2165_write_reg_list(state, dvbc_regs, ARRAY_SIZE(dvbc_regs)); if (ret < 0) return ret; - ret = si2165_writereg8(state, 0x0387, 0x00); + + return 0; +} + +static const struct si2165_reg_value_pair agc_rewrite[] = { + { 0x012a, 0x46 }, + { 0x012c, 0x00 }, + { 0x012e, 0x0a }, + { 0x012f, 0xff }, + { 0x0123, 0x70 } +}; + +static int si2165_set_frontend(struct dvb_frontend *fe) +{ + struct si2165_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + u32 delsys = p->delivery_system; + int ret; + u8 val[3]; + + /* initial setting of if freq shift */ + ret = si2165_set_if_freq_shift(state); if (ret < 0) return ret; + + switch (delsys) { + case SYS_DVBT: + ret = si2165_set_frontend_dvbt(fe); + if (ret < 0) + return ret; + break; + case SYS_DVBC_ANNEX_A: + ret = si2165_set_frontend_dvbc(fe); + if (ret < 0) + return ret; + break; + default: + return -EINVAL; + } + /* dsp_addr_jump */ ret = si2165_writereg32(state, 0x0348, 0xf4000000); if (ret < 0) @@ -874,8 +968,7 @@ static int si2165_set_parameters(struct dvb_frontend *fe) fe->ops.tuner_ops.set_params(fe); /* recalc if_freq_shift if IF might has changed */ - fe->ops.tuner_ops.get_if_frequency(fe, &IF); - ret = si2165_set_if_freq_shift(state, IF); + ret = si2165_set_if_freq_shift(state); if (ret < 0) return ret; @@ -886,6 +979,7 @@ static int si2165_set_parameters(struct dvb_frontend *fe) ret = si2165_writereg8(state, 0x0341, 0x00); if (ret < 0) return ret; + /* reset all */ ret = si2165_writereg8(state, 0x00c0, 0x00); if (ret < 0) @@ -894,6 +988,13 @@ static int si2165_set_parameters(struct dvb_frontend *fe) ret = si2165_writereg32(state, 0x0384, 0x00000000); if (ret < 0) return ret; + + /* write adc values after each reset*/ + ret = si2165_write_reg_list(state, agc_rewrite, + ARRAY_SIZE(agc_rewrite)); + if (ret < 0) + return ret; + /* start_synchro */ ret = si2165_writereg8(state, 0x02e0, 0x01); if (ret < 0) @@ -917,7 +1018,12 @@ static void si2165_release(struct dvb_frontend *fe) static struct dvb_frontend_ops si2165_ops = { .info = { .name = "Silicon Labs ", - .caps = FE_CAN_FEC_1_2 | + /* For DVB-C */ + .symbol_rate_min = 1000000, + .symbol_rate_max = 7200000, + /* For DVB-T */ + .frequency_stepsize = 166667, + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | @@ -930,7 +1036,6 @@ static struct dvb_frontend_ops si2165_ops = { FE_CAN_QAM_128 | FE_CAN_QAM_256 | FE_CAN_QAM_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO | FE_CAN_MUTE_TS | @@ -943,7 +1048,7 @@ static struct dvb_frontend_ops si2165_ops = { .init = si2165_init, .sleep = si2165_sleep, - .set_frontend = si2165_set_parameters, + .set_frontend = si2165_set_frontend, .read_status = si2165_read_status, .release = si2165_release, @@ -979,9 +1084,9 @@ struct dvb_frontend *si2165_attach(const struct si2165_config *config, } /* create dvb_frontend */ - memcpy(&state->frontend.ops, &si2165_ops, + memcpy(&state->fe.ops, &si2165_ops, sizeof(struct dvb_frontend_ops)); - state->frontend.demodulator_priv = state; + state->fe.demodulator_priv = state; /* powerup */ io_ret = si2165_writereg8(state, 0x0000, state->config.chip_mode); @@ -1033,20 +1138,22 @@ struct dvb_frontend *si2165_attach(const struct si2165_config *config, KBUILD_MODNAME, chip_name, rev_char, state->chip_type, state->chip_revcode); - strlcat(state->frontend.ops.info.name, chip_name, - sizeof(state->frontend.ops.info.name)); + strlcat(state->fe.ops.info.name, chip_name, + sizeof(state->fe.ops.info.name)); n = 0; if (state->has_dvbt) { - state->frontend.ops.delsys[n++] = SYS_DVBT; - strlcat(state->frontend.ops.info.name, " DVB-T", - sizeof(state->frontend.ops.info.name)); + state->fe.ops.delsys[n++] = SYS_DVBT; + strlcat(state->fe.ops.info.name, " DVB-T", + sizeof(state->fe.ops.info.name)); + } + if (state->has_dvbc) { + state->fe.ops.delsys[n++] = SYS_DVBC_ANNEX_A; + strlcat(state->fe.ops.info.name, " DVB-C", + sizeof(state->fe.ops.info.name)); } - if (state->has_dvbc) - dev_warn(&state->i2c->dev, "%s: DVB-C is not yet supported.\n", - KBUILD_MODNAME); - return &state->frontend; + return &state->fe; error: kfree(state); diff --git a/drivers/media/dvb-frontends/stb6100.c b/drivers/media/dvb-frontends/stb6100.c index 4ef8a5c70..c978c801c 100644 --- a/drivers/media/dvb-frontends/stb6100.c +++ b/drivers/media/dvb-frontends/stb6100.c @@ -252,6 +252,7 @@ static int stb6100_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) { int rc; u8 f; + u32 bw; struct stb6100_state *state = fe->tuner_priv; rc = stb6100_read_reg(state, STB6100_F); @@ -259,9 +260,9 @@ static int stb6100_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) return rc; f = rc & STB6100_F_F; - state->status.bandwidth = (f + 5) * 2000; /* x2 for ZIF */ + bw = (f + 5) * 2000; /* x2 for ZIF */ - *bandwidth = state->bandwidth = state->status.bandwidth * 1000; + *bandwidth = state->bandwidth = bw * 1000; dprintk(verbose, FE_DEBUG, 1, "bandwidth = %u Hz", state->bandwidth); return 0; } @@ -495,68 +496,28 @@ static int stb6100_sleep(struct dvb_frontend *fe) static int stb6100_init(struct dvb_frontend *fe) { struct stb6100_state *state = fe->tuner_priv; - struct tuner_state *status = &state->status; + int refclk = 27000000; /* Hz */ - status->tunerstep = 125000; - status->ifreq = 0; - status->refclock = 27000000; /* Hz */ - status->iqsense = 1; - status->bandwidth = 36000; /* kHz */ - state->bandwidth = status->bandwidth * 1000; /* Hz */ - state->reference = status->refclock / 1000; /* kHz */ + /* + * iqsense = 1 + * tunerstep = 125000 + */ + state->bandwidth = 36000000; /* Hz */ + state->reference = refclk / 1000; /* kHz */ /* Set default bandwidth. Modified, PN 13-May-10 */ return 0; } -static int stb6100_get_state(struct dvb_frontend *fe, - enum tuner_param param, - struct tuner_state *state) +static int stb6100_set_params(struct dvb_frontend *fe) { - switch (param) { - case DVBFE_TUNER_FREQUENCY: - stb6100_get_frequency(fe, &state->frequency); - break; - case DVBFE_TUNER_TUNERSTEP: - break; - case DVBFE_TUNER_IFFREQ: - break; - case DVBFE_TUNER_BANDWIDTH: - stb6100_get_bandwidth(fe, &state->bandwidth); - break; - case DVBFE_TUNER_REFCLOCK: - break; - default: - break; - } + struct dtv_frontend_properties *c = &fe->dtv_property_cache; - return 0; -} + if (c->frequency > 0) + stb6100_set_frequency(fe, c->frequency); -static int stb6100_set_state(struct dvb_frontend *fe, - enum tuner_param param, - struct tuner_state *state) -{ - struct stb6100_state *tstate = fe->tuner_priv; - - switch (param) { - case DVBFE_TUNER_FREQUENCY: - stb6100_set_frequency(fe, state->frequency); - tstate->frequency = state->frequency; - break; - case DVBFE_TUNER_TUNERSTEP: - break; - case DVBFE_TUNER_IFFREQ: - break; - case DVBFE_TUNER_BANDWIDTH: - stb6100_set_bandwidth(fe, state->bandwidth); - tstate->bandwidth = state->bandwidth; - break; - case DVBFE_TUNER_REFCLOCK: - break; - default: - break; - } + if (c->bandwidth_hz > 0) + stb6100_set_bandwidth(fe, c->bandwidth_hz); return 0; } @@ -572,8 +533,9 @@ static struct dvb_tuner_ops stb6100_ops = { .init = stb6100_init, .sleep = stb6100_sleep, .get_status = stb6100_get_status, - .get_state = stb6100_get_state, - .set_state = stb6100_set_state, + .set_params = stb6100_set_params, + .get_frequency = stb6100_get_frequency, + .get_bandwidth = stb6100_get_bandwidth, .release = stb6100_release }; diff --git a/drivers/media/dvb-frontends/stb6100.h b/drivers/media/dvb-frontends/stb6100.h index 218c81888..f7b468b6d 100644 --- a/drivers/media/dvb-frontends/stb6100.h +++ b/drivers/media/dvb-frontends/stb6100.h @@ -86,7 +86,6 @@ struct stb6100_state { const struct stb6100_config *config; struct dvb_tuner_ops ops; struct dvb_frontend *frontend; - struct tuner_state status; u32 frequency; u32 srate; diff --git a/drivers/media/dvb-frontends/stb6100_cfg.h b/drivers/media/dvb-frontends/stb6100_cfg.h index 6edc15365..2ef67aa76 100644 --- a/drivers/media/dvb-frontends/stb6100_cfg.h +++ b/drivers/media/dvb-frontends/stb6100_cfg.h @@ -19,20 +19,21 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include <linux/dvb/frontend.h> +#include "dvb_frontend.h" + static int stb6100_get_frequency(struct dvb_frontend *fe, u32 *frequency) { struct dvb_frontend_ops *frontend_ops = &fe->ops; struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops; - struct tuner_state t_state; int err = 0; - if (tuner_ops->get_state) { - err = tuner_ops->get_state(fe, DVBFE_TUNER_FREQUENCY, &t_state); + if (tuner_ops->get_frequency) { + err = tuner_ops->get_frequency(fe, frequency); if (err < 0) { printk("%s: Invalid parameter\n", __func__); return err; } - *frequency = t_state.frequency; } return 0; } @@ -41,13 +42,16 @@ static int stb6100_set_frequency(struct dvb_frontend *fe, u32 frequency) { struct dvb_frontend_ops *frontend_ops = &fe->ops; struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops; - struct tuner_state t_state; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 bw = c->bandwidth_hz; int err = 0; - t_state.frequency = frequency; + c->frequency = frequency; + c->bandwidth_hz = 0; /* Don't adjust the bandwidth */ - if (tuner_ops->set_state) { - err = tuner_ops->set_state(fe, DVBFE_TUNER_FREQUENCY, &t_state); + if (tuner_ops->set_params) { + err = tuner_ops->set_params(fe); + c->bandwidth_hz = bw; if (err < 0) { printk("%s: Invalid parameter\n", __func__); return err; @@ -60,16 +64,14 @@ static int stb6100_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) { struct dvb_frontend_ops *frontend_ops = &fe->ops; struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops; - struct tuner_state t_state; int err = 0; - if (tuner_ops->get_state) { - err = tuner_ops->get_state(fe, DVBFE_TUNER_BANDWIDTH, &t_state); + if (tuner_ops->get_bandwidth) { + err = tuner_ops->get_bandwidth(fe, bandwidth); if (err < 0) { printk("%s: Invalid parameter\n", __func__); return err; } - *bandwidth = t_state.bandwidth; } return 0; } @@ -78,13 +80,16 @@ static int stb6100_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth) { struct dvb_frontend_ops *frontend_ops = &fe->ops; struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops; - struct tuner_state t_state; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 freq = c->frequency; int err = 0; - t_state.bandwidth = bandwidth; + c->bandwidth_hz = bandwidth; + c->frequency = 0; /* Don't adjust the frequency */ - if (tuner_ops->set_state) { - err = tuner_ops->set_state(fe, DVBFE_TUNER_BANDWIDTH, &t_state); + if (tuner_ops->set_params) { + err = tuner_ops->set_params(fe); + c->frequency = freq; if (err < 0) { printk("%s: Invalid parameter\n", __func__); return err; diff --git a/drivers/media/dvb-frontends/stb6100_proc.h b/drivers/media/dvb-frontends/stb6100_proc.h index bd8a0ec9e..50ffa21e3 100644 --- a/drivers/media/dvb-frontends/stb6100_proc.h +++ b/drivers/media/dvb-frontends/stb6100_proc.h @@ -17,27 +17,27 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include <linux/dvb/frontend.h> +#include "dvb_frontend.h" + static int stb6100_get_freq(struct dvb_frontend *fe, u32 *frequency) { struct dvb_frontend_ops *frontend_ops = &fe->ops; struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops; - struct tuner_state state; int err = 0; - if (tuner_ops->get_state) { + if (tuner_ops->get_frequency) { if (frontend_ops->i2c_gate_ctrl) frontend_ops->i2c_gate_ctrl(fe, 1); - err = tuner_ops->get_state(fe, DVBFE_TUNER_FREQUENCY, &state); + err = tuner_ops->get_frequency(fe, frequency); if (err < 0) { - printk(KERN_ERR "%s: Invalid parameter\n", __func__); + printk("%s: Invalid parameter\n", __func__); return err; } if (frontend_ops->i2c_gate_ctrl) frontend_ops->i2c_gate_ctrl(fe, 0); - - *frequency = state.frequency; } return 0; @@ -47,18 +47,21 @@ static int stb6100_set_freq(struct dvb_frontend *fe, u32 frequency) { struct dvb_frontend_ops *frontend_ops = &fe->ops; struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops; - struct tuner_state state; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 bw = c->bandwidth_hz; int err = 0; - state.frequency = frequency; + c->frequency = frequency; + c->bandwidth_hz = 0; /* Don't adjust the bandwidth */ - if (tuner_ops->set_state) { + if (tuner_ops->set_params) { if (frontend_ops->i2c_gate_ctrl) frontend_ops->i2c_gate_ctrl(fe, 1); - err = tuner_ops->set_state(fe, DVBFE_TUNER_FREQUENCY, &state); + err = tuner_ops->set_params(fe); + c->bandwidth_hz = bw; if (err < 0) { - printk(KERN_ERR "%s: Invalid parameter\n", __func__); + printk("%s: Invalid parameter\n", __func__); return err; } @@ -74,14 +77,13 @@ static int stb6100_get_bandw(struct dvb_frontend *fe, u32 *bandwidth) { struct dvb_frontend_ops *frontend_ops = &fe->ops; struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops; - struct tuner_state state; int err = 0; - if (tuner_ops->get_state) { + if (tuner_ops->get_bandwidth) { if (frontend_ops->i2c_gate_ctrl) frontend_ops->i2c_gate_ctrl(fe, 1); - err = tuner_ops->get_state(fe, DVBFE_TUNER_BANDWIDTH, &state); + err = tuner_ops->get_bandwidth(fe, bandwidth); if (err < 0) { printk(KERN_ERR "%s: Invalid parameter\n", __func__); return err; @@ -89,8 +91,6 @@ static int stb6100_get_bandw(struct dvb_frontend *fe, u32 *bandwidth) if (frontend_ops->i2c_gate_ctrl) frontend_ops->i2c_gate_ctrl(fe, 0); - - *bandwidth = state.bandwidth; } return 0; @@ -100,16 +100,19 @@ static int stb6100_set_bandw(struct dvb_frontend *fe, u32 bandwidth) { struct dvb_frontend_ops *frontend_ops = &fe->ops; struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops; - struct tuner_state state; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 freq = c->frequency; int err = 0; - state.bandwidth = bandwidth; + c->bandwidth_hz = bandwidth; + c->frequency = 0; /* Don't adjust the frequency */ - if (tuner_ops->set_state) { + if (tuner_ops->set_params) { if (frontend_ops->i2c_gate_ctrl) frontend_ops->i2c_gate_ctrl(fe, 1); - err = tuner_ops->set_state(fe, DVBFE_TUNER_BANDWIDTH, &state); + err = tuner_ops->set_params(fe); + c->frequency = freq; if (err < 0) { printk(KERN_ERR "%s: Invalid parameter\n", __func__); return err; diff --git a/drivers/media/dvb-frontends/tda665x.c b/drivers/media/dvb-frontends/tda665x.c index 63cc12378..82f8cc534 100644 --- a/drivers/media/dvb-frontends/tda665x.c +++ b/drivers/media/dvb-frontends/tda665x.c @@ -66,26 +66,13 @@ exit: return err; } -static int tda665x_get_state(struct dvb_frontend *fe, - enum tuner_param param, - struct tuner_state *tstate) +static int tda665x_get_frequency(struct dvb_frontend *fe, u32 *frequency) { struct tda665x_state *state = fe->tuner_priv; - int err = 0; - switch (param) { - case DVBFE_TUNER_FREQUENCY: - tstate->frequency = state->frequency; - break; - case DVBFE_TUNER_BANDWIDTH: - break; - default: - printk(KERN_ERR "%s: Unknown parameter (param=%d)\n", __func__, param); - err = -EINVAL; - break; - } + *frequency = state->frequency; - return err; + return 0; } static int tda665x_get_status(struct dvb_frontend *fe, u32 *status) @@ -111,9 +98,8 @@ exit: return err; } -static int tda665x_set_state(struct dvb_frontend *fe, - enum tuner_param param, - struct tuner_state *tstate) +static int tda665x_set_frequency(struct dvb_frontend *fe, + u32 new_frequency) { struct tda665x_state *state = fe->tuner_priv; const struct tda665x_config *config = state->config; @@ -121,88 +107,96 @@ static int tda665x_set_state(struct dvb_frontend *fe, u8 buf[4]; int err = 0; - if (param & DVBFE_TUNER_FREQUENCY) { - - frequency = tstate->frequency; - if ((frequency < config->frequency_max) || (frequency > config->frequency_min)) { - printk(KERN_ERR "%s: Frequency beyond limits, frequency=%d\n", __func__, frequency); - return -EINVAL; - } - - frequency += config->frequency_offst; - frequency *= config->ref_multiplier; - frequency += config->ref_divider >> 1; - frequency /= config->ref_divider; - - buf[0] = (u8) ((frequency & 0x7f00) >> 8); - buf[1] = (u8) (frequency & 0x00ff) >> 0; - buf[2] = 0x80 | 0x40 | 0x02; - buf[3] = 0x00; - - /* restore frequency */ - frequency = tstate->frequency; - - if (frequency < 153000000) { - /* VHF-L */ - buf[3] |= 0x01; /* fc, Low Band, 47 - 153 MHz */ - if (frequency < 68000000) - buf[3] |= 0x40; /* 83uA */ - if (frequency < 1040000000) - buf[3] |= 0x60; /* 122uA */ - if (frequency < 1250000000) - buf[3] |= 0x80; /* 163uA */ - else - buf[3] |= 0xa0; /* 254uA */ - } else if (frequency < 438000000) { - /* VHF-H */ - buf[3] |= 0x02; /* fc, Mid Band, 153 - 438 MHz */ - if (frequency < 230000000) - buf[3] |= 0x40; - if (frequency < 300000000) - buf[3] |= 0x60; - else - buf[3] |= 0x80; - } else { - /* UHF */ - buf[3] |= 0x04; /* fc, High Band, 438 - 862 MHz */ - if (frequency < 470000000) - buf[3] |= 0x60; - if (frequency < 526000000) - buf[3] |= 0x80; - else - buf[3] |= 0xa0; - } - - /* Set params */ - err = tda665x_write(state, buf, 5); - if (err < 0) - goto exit; - - /* sleep for some time */ - printk(KERN_DEBUG "%s: Waiting to Phase LOCK\n", __func__); - msleep(20); - /* check status */ - err = tda665x_get_status(fe, &status); - if (err < 0) - goto exit; - - if (status == 1) { - printk(KERN_DEBUG "%s: Tuner Phase locked: status=%d\n", __func__, status); - state->frequency = frequency; /* cache successful state */ - } else { - printk(KERN_ERR "%s: No Phase lock: status=%d\n", __func__, status); - } - } else { - printk(KERN_ERR "%s: Unknown parameter (param=%d)\n", __func__, param); + if ((new_frequency < config->frequency_max) + || (new_frequency > config->frequency_min)) { + printk(KERN_ERR "%s: Frequency beyond limits, frequency=%d\n", + __func__, new_frequency); return -EINVAL; } + frequency = new_frequency; + + frequency += config->frequency_offst; + frequency *= config->ref_multiplier; + frequency += config->ref_divider >> 1; + frequency /= config->ref_divider; + + buf[0] = (u8) ((frequency & 0x7f00) >> 8); + buf[1] = (u8) (frequency & 0x00ff) >> 0; + buf[2] = 0x80 | 0x40 | 0x02; + buf[3] = 0x00; + + /* restore frequency */ + frequency = new_frequency; + + if (frequency < 153000000) { + /* VHF-L */ + buf[3] |= 0x01; /* fc, Low Band, 47 - 153 MHz */ + if (frequency < 68000000) + buf[3] |= 0x40; /* 83uA */ + if (frequency < 1040000000) + buf[3] |= 0x60; /* 122uA */ + if (frequency < 1250000000) + buf[3] |= 0x80; /* 163uA */ + else + buf[3] |= 0xa0; /* 254uA */ + } else if (frequency < 438000000) { + /* VHF-H */ + buf[3] |= 0x02; /* fc, Mid Band, 153 - 438 MHz */ + if (frequency < 230000000) + buf[3] |= 0x40; + if (frequency < 300000000) + buf[3] |= 0x60; + else + buf[3] |= 0x80; + } else { + /* UHF */ + buf[3] |= 0x04; /* fc, High Band, 438 - 862 MHz */ + if (frequency < 470000000) + buf[3] |= 0x60; + if (frequency < 526000000) + buf[3] |= 0x80; + else + buf[3] |= 0xa0; + } + + /* Set params */ + err = tda665x_write(state, buf, 5); + if (err < 0) + goto exit; + + /* sleep for some time */ + printk(KERN_DEBUG "%s: Waiting to Phase LOCK\n", __func__); + msleep(20); + /* check status */ + err = tda665x_get_status(fe, &status); + if (err < 0) + goto exit; + + if (status == 1) { + printk(KERN_DEBUG "%s: Tuner Phase locked: status=%d\n", + __func__, status); + state->frequency = frequency; /* cache successful state */ + } else { + printk(KERN_ERR "%s: No Phase lock: status=%d\n", + __func__, status); + } + return 0; exit: printk(KERN_ERR "%s: I/O Error\n", __func__); return err; } +static int tda665x_set_params(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + + tda665x_set_frequency(fe, c->frequency); + + return 0; +} + static int tda665x_release(struct dvb_frontend *fe) { struct tda665x_state *state = fe->tuner_priv; @@ -213,10 +207,9 @@ static int tda665x_release(struct dvb_frontend *fe) } static struct dvb_tuner_ops tda665x_ops = { - - .set_state = tda665x_set_state, - .get_state = tda665x_get_state, .get_status = tda665x_get_status, + .set_params = tda665x_set_params, + .get_frequency = tda665x_get_frequency, .release = tda665x_release }; diff --git a/drivers/media/dvb-frontends/tda8261.c b/drivers/media/dvb-frontends/tda8261.c index 19c488814..3285b1bc4 100644 --- a/drivers/media/dvb-frontends/tda8261.c +++ b/drivers/media/dvb-frontends/tda8261.c @@ -83,88 +83,71 @@ static int tda8261_get_status(struct dvb_frontend *fe, u32 *status) static const u32 div_tab[] = { 2000, 1000, 500, 250, 125 }; /* kHz */ static const u8 ref_div[] = { 0x00, 0x01, 0x02, 0x05, 0x07 }; -static int tda8261_get_state(struct dvb_frontend *fe, - enum tuner_param param, - struct tuner_state *tstate) +static int tda8261_get_frequency(struct dvb_frontend *fe, u32 *frequency) { struct tda8261_state *state = fe->tuner_priv; - int err = 0; - switch (param) { - case DVBFE_TUNER_FREQUENCY: - tstate->frequency = state->frequency; - break; - case DVBFE_TUNER_BANDWIDTH: - tstate->bandwidth = 40000000; /* FIXME! need to calculate Bandwidth */ - break; - default: - pr_err("%s: Unknown parameter (param=%d)\n", __func__, param); - err = -EINVAL; - break; - } + *frequency = state->frequency; - return err; + return 0; } -static int tda8261_set_state(struct dvb_frontend *fe, - enum tuner_param param, - struct tuner_state *tstate) +static int tda8261_set_params(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct tda8261_state *state = fe->tuner_priv; const struct tda8261_config *config = state->config; u32 frequency, N, status = 0; u8 buf[4]; int err = 0; - if (param & DVBFE_TUNER_FREQUENCY) { - /** - * N = Max VCO Frequency / Channel Spacing - * Max VCO Frequency = VCO frequency + (channel spacing - 1) - * (to account for half channel spacing on either side) - */ - frequency = tstate->frequency; - if ((frequency < 950000) || (frequency > 2150000)) { - pr_warn("%s: Frequency beyond limits, frequency=%d\n", __func__, frequency); - return -EINVAL; - } - N = (frequency + (div_tab[config->step_size] - 1)) / div_tab[config->step_size]; - pr_debug("%s: Step size=%d, Divider=%d, PG=0x%02x (%d)\n", - __func__, config->step_size, div_tab[config->step_size], N, N); - - buf[0] = (N >> 8) & 0xff; - buf[1] = N & 0xff; - buf[2] = (0x01 << 7) | ((ref_div[config->step_size] & 0x07) << 1); - - if (frequency < 1450000) - buf[3] = 0x00; - else if (frequency < 2000000) - buf[3] = 0x40; - else if (frequency < 2150000) - buf[3] = 0x80; - - /* Set params */ - if ((err = tda8261_write(state, buf)) < 0) { - pr_err("%s: I/O Error\n", __func__); - return err; - } - /* sleep for some time */ - pr_debug("%s: Waiting to Phase LOCK\n", __func__); - msleep(20); - /* check status */ - if ((err = tda8261_get_status(fe, &status)) < 0) { - pr_err("%s: I/O Error\n", __func__); - return err; - } - if (status == 1) { - pr_debug("%s: Tuner Phase locked: status=%d\n", __func__, status); - state->frequency = frequency; /* cache successful state */ - } else { - pr_debug("%s: No Phase lock: status=%d\n", __func__, status); - } - } else { - pr_err("%s: Unknown parameter (param=%d)\n", __func__, param); + /* + * N = Max VCO Frequency / Channel Spacing + * Max VCO Frequency = VCO frequency + (channel spacing - 1) + * (to account for half channel spacing on either side) + */ + frequency = c->frequency; + if ((frequency < 950000) || (frequency > 2150000)) { + pr_warn("%s: Frequency beyond limits, frequency=%d\n", + __func__, frequency); return -EINVAL; } + N = (frequency + (div_tab[config->step_size] - 1)) / div_tab[config->step_size]; + pr_debug("%s: Step size=%d, Divider=%d, PG=0x%02x (%d)\n", + __func__, config->step_size, div_tab[config->step_size], N, N); + + buf[0] = (N >> 8) & 0xff; + buf[1] = N & 0xff; + buf[2] = (0x01 << 7) | ((ref_div[config->step_size] & 0x07) << 1); + + if (frequency < 1450000) + buf[3] = 0x00; + else if (frequency < 2000000) + buf[3] = 0x40; + else if (frequency < 2150000) + buf[3] = 0x80; + + /* Set params */ + err = tda8261_write(state, buf); + if (err < 0) { + pr_err("%s: I/O Error\n", __func__); + return err; + } + /* sleep for some time */ + pr_debug("%s: Waiting to Phase LOCK\n", __func__); + msleep(20); + /* check status */ + if ((err = tda8261_get_status(fe, &status)) < 0) { + pr_err("%s: I/O Error\n", __func__); + return err; + } + if (status == 1) { + pr_debug("%s: Tuner Phase locked: status=%d\n", __func__, + status); + state->frequency = frequency; /* cache successful state */ + } else { + pr_debug("%s: No Phase lock: status=%d\n", __func__, status); + } return 0; } @@ -182,14 +165,13 @@ static struct dvb_tuner_ops tda8261_ops = { .info = { .name = "TDA8261", -// .tuner_name = NULL, .frequency_min = 950000, .frequency_max = 2150000, .frequency_step = 0 }, - .set_state = tda8261_set_state, - .get_state = tda8261_get_state, + .set_params = tda8261_set_params, + .get_frequency = tda8261_get_frequency, .get_status = tda8261_get_status, .release = tda8261_release }; @@ -210,10 +192,7 @@ struct dvb_frontend *tda8261_attach(struct dvb_frontend *fe, fe->ops.tuner_ops = tda8261_ops; fe->ops.tuner_ops.info.frequency_step = div_tab[config->step_size]; -// fe->ops.tuner_ops.tuner_name = &config->buf; -// printk("%s: Attaching %s TDA8261 8PSK/QPSK tuner\n", -// __func__, fe->ops.tuner_ops.tuner_name); pr_info("%s: Attaching TDA8261 8PSK/QPSK tuner\n", __func__); return fe; diff --git a/drivers/media/dvb-frontends/tda8261_cfg.h b/drivers/media/dvb-frontends/tda8261_cfg.h index 04a19e14e..fe527ff84 100644 --- a/drivers/media/dvb-frontends/tda8261_cfg.h +++ b/drivers/media/dvb-frontends/tda8261_cfg.h @@ -21,17 +21,15 @@ static int tda8261_get_frequency(struct dvb_frontend *fe, u32 *frequency) { struct dvb_frontend_ops *frontend_ops = &fe->ops; struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops; - struct tuner_state t_state; int err = 0; - if (tuner_ops->get_state) { - err = tuner_ops->get_state(fe, DVBFE_TUNER_FREQUENCY, &t_state); + if (tuner_ops->get_frequency) { + err = tuner_ops->get_frequency(fe, frequency); if (err < 0) { - printk("%s: Invalid parameter\n", __func__); + pr_err("%s: Invalid parameter\n", __func__); return err; } - *frequency = t_state.frequency; - printk("%s: Frequency=%d\n", __func__, t_state.frequency); + pr_debug("%s: Frequency=%d\n", __func__, *frequency); } return 0; } @@ -40,37 +38,24 @@ static int tda8261_set_frequency(struct dvb_frontend *fe, u32 frequency) { struct dvb_frontend_ops *frontend_ops = &fe->ops; struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops; - struct tuner_state t_state; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; int err = 0; - t_state.frequency = frequency; - - if (tuner_ops->set_state) { - err = tuner_ops->set_state(fe, DVBFE_TUNER_FREQUENCY, &t_state); + if (tuner_ops->set_params) { + err = tuner_ops->set_params(fe); if (err < 0) { - printk("%s: Invalid parameter\n", __func__); + pr_err("%s: Invalid parameter\n", __func__); return err; } } - printk("%s: Frequency=%d\n", __func__, t_state.frequency); + pr_debug("%s: Frequency=%d\n", __func__, c->frequency); return 0; } static int tda8261_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) { - struct dvb_frontend_ops *frontend_ops = &fe->ops; - struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops; - struct tuner_state t_state; - int err = 0; + /* FIXME! need to calculate Bandwidth */ + *bandwidth = 40000000; - if (tuner_ops->get_state) { - err = tuner_ops->get_state(fe, DVBFE_TUNER_BANDWIDTH, &t_state); - if (err < 0) { - printk("%s: Invalid parameter\n", __func__); - return err; - } - *bandwidth = t_state.bandwidth; - printk("%s: Bandwidth=%d\n", __func__, t_state.bandwidth); - } return 0; } diff --git a/drivers/media/dvb-frontends/tdhd1.h b/drivers/media/dvb-frontends/tdhd1.h index 17750985d..2b9e8732c 100644 --- a/drivers/media/dvb-frontends/tdhd1.h +++ b/drivers/media/dvb-frontends/tdhd1.h @@ -20,7 +20,7 @@ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * * - * The project's page is at http://www.linuxtv.org + * The project's page is at https://linuxtv.org */ #ifndef TDHD1_H diff --git a/drivers/media/firewire/firedtv-ci.c b/drivers/media/firewire/firedtv-ci.c index e63f58237..edbb30fdd 100644 --- a/drivers/media/firewire/firedtv-ci.c +++ b/drivers/media/firewire/firedtv-ci.c @@ -241,7 +241,7 @@ int fdtv_ca_register(struct firedtv *fdtv) return -EFAULT; err = dvb_register_device(&fdtv->adapter, &fdtv->cadev, - &fdtv_ca, fdtv, DVB_DEVICE_CA); + &fdtv_ca, fdtv, DVB_DEVICE_CA, 0); if (stat.ca_application_info == 0) dev_err(fdtv->device, "CaApplicationInfo is not set\n"); diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 521bbf1b2..993dc50c1 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -83,6 +83,16 @@ config VIDEO_MSP3400 To compile this driver as a module, choose M here: the module will be called msp3400. +config VIDEO_CS3308 + tristate "Cirrus Logic CS3308 audio ADC" + depends on VIDEO_V4L2 && I2C + ---help--- + Support for the Cirrus Logic CS3308 High Performance 8-Channel + Analog Volume Control + + To compile this driver as a module, choose M here: the + module will be called cs3308. + config VIDEO_CS5345 tristate "Cirrus Logic CS5345 audio ADC" depends on VIDEO_V4L2 && I2C diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index 07db257ab..94f2c99e8 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -43,6 +43,7 @@ obj-$(CONFIG_VIDEO_TVP7002) += tvp7002.o obj-$(CONFIG_VIDEO_TW2804) += tw2804.o obj-$(CONFIG_VIDEO_TW9903) += tw9903.o obj-$(CONFIG_VIDEO_TW9906) += tw9906.o +obj-$(CONFIG_VIDEO_CS3308) += cs3308.o obj-$(CONFIG_VIDEO_CS5345) += cs5345.o obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o obj-$(CONFIG_VIDEO_M52790) += m52790.o diff --git a/drivers/media/i2c/ad9389b.c b/drivers/media/i2c/ad9389b.c index 69094ab04..788967dad 100644 --- a/drivers/media/i2c/ad9389b.c +++ b/drivers/media/i2c/ad9389b.c @@ -35,7 +35,7 @@ #include <media/v4l2-common.h> #include <media/v4l2-dv-timings.h> #include <media/v4l2-ctrls.h> -#include <media/ad9389b.h> +#include <media/i2c/ad9389b.h> static int debug; module_param(debug, int, 0644); @@ -1158,7 +1158,7 @@ static int ad9389b_probe(struct i2c_client *client, const struct i2c_device_id * state->rgb_quantization_range_ctrl->is_private = true; state->pad.flags = MEDIA_PAD_FL_SINK; - err = media_entity_init(&sd->entity, 1, &state->pad, 0); + err = media_entity_pads_init(&sd->entity, 1, &state->pad); if (err) goto err_hdl; diff --git a/drivers/media/i2c/adp1653.c b/drivers/media/i2c/adp1653.c index 5dd39775d..fb7ed730d 100644 --- a/drivers/media/i2c/adp1653.c +++ b/drivers/media/i2c/adp1653.c @@ -37,7 +37,7 @@ #include <linux/slab.h> #include <linux/of.h> #include <linux/gpio/consumer.h> -#include <media/adp1653.h> +#include <media/i2c/adp1653.h> #include <media/v4l2-device.h> #define TIMEOUT_MAX 820000 @@ -497,7 +497,7 @@ static int adp1653_probe(struct i2c_client *client, if (!client->dev.platform_data) { dev_err(&client->dev, "Neither DT not platform data provided\n"); - return EINVAL; + return -EINVAL; } flash->platform_data = client->dev.platform_data; } @@ -512,11 +512,11 @@ static int adp1653_probe(struct i2c_client *client, if (ret) goto free_and_quit; - ret = media_entity_init(&flash->subdev.entity, 0, NULL, 0); + ret = media_entity_pads_init(&flash->subdev.entity, 0, NULL); if (ret < 0) goto free_and_quit; - flash->subdev.entity.type = MEDIA_ENT_T_V4L2_SUBDEV_FLASH; + flash->subdev.entity.function = MEDIA_ENT_F_FLASH; return 0; diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c index f82c8aa16..ff57c1dcb 100644 --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c @@ -1112,7 +1112,7 @@ static int init_device(struct adv7180_state *state) mutex_lock(&state->mutex); adv7180_write(state, ADV7180_REG_PWR_MAN, ADV7180_PWR_MAN_RES); - usleep_range(2000, 10000); + usleep_range(5000, 10000); ret = state->chip_info->init(state); if (ret) @@ -1213,8 +1213,8 @@ static int adv7180_probe(struct i2c_client *client, goto err_unregister_vpp_client; state->pad.flags = MEDIA_PAD_FL_SOURCE; - sd->entity.flags |= MEDIA_ENT_T_V4L2_SUBDEV_DECODER; - ret = media_entity_init(&sd->entity, 1, &state->pad, 0); + sd->entity.flags |= MEDIA_ENT_F_ATV_DECODER; + ret = media_entity_pads_init(&sd->entity, 1, &state->pad); if (ret) goto err_free_ctrl; diff --git a/drivers/media/i2c/adv7183.c b/drivers/media/i2c/adv7183.c index e2dd16176..2bec73788 100644 --- a/drivers/media/i2c/adv7183.c +++ b/drivers/media/i2c/adv7183.c @@ -27,7 +27,7 @@ #include <linux/types.h> #include <linux/videodev2.h> -#include <media/adv7183.h> +#include <media/i2c/adv7183.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> diff --git a/drivers/media/i2c/adv7343.c b/drivers/media/i2c/adv7343.c index f89d0afcd..11f902943 100644 --- a/drivers/media/i2c/adv7343.c +++ b/drivers/media/i2c/adv7343.c @@ -28,7 +28,7 @@ #include <linux/of.h> #include <linux/of_graph.h> -#include <media/adv7343.h> +#include <media/i2c/adv7343.h> #include <media/v4l2-async.h> #include <media/v4l2-device.h> #include <media/v4l2-ctrls.h> diff --git a/drivers/media/i2c/adv7393.c b/drivers/media/i2c/adv7393.c index 0215f95c2..76d987476 100644 --- a/drivers/media/i2c/adv7393.c +++ b/drivers/media/i2c/adv7393.c @@ -31,7 +31,7 @@ #include <linux/videodev2.h> #include <linux/uaccess.h> -#include <media/adv7393.h> +#include <media/i2c/adv7393.h> #include <media/v4l2-device.h> #include <media/v4l2-ctrls.h> diff --git a/drivers/media/i2c/adv7511.c b/drivers/media/i2c/adv7511.c index e4900df11..471fd23b5 100644 --- a/drivers/media/i2c/adv7511.c +++ b/drivers/media/i2c/adv7511.c @@ -32,7 +32,7 @@ #include <media/v4l2-common.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-dv-timings.h> -#include <media/adv7511.h> +#include <media/i2c/adv7511.h> static int debug; module_param(debug, int, 0644); @@ -1116,7 +1116,7 @@ static int adv7511_set_fmt(struct v4l2_subdev *sd, adv7511_wr_and_or(sd, 0x55, 0x9f, y << 5); adv7511_wr_and_or(sd, 0x56, 0x3f, c << 6); adv7511_wr_and_or(sd, 0x57, 0x83, (ec << 4) | (q << 2)); - adv7511_wr_and_or(sd, 0x59, 0x0f, yq << 4); + adv7511_wr_and_or(sd, 0x59, 0x3f, yq << 6); adv7511_wr_and_or(sd, 0x4a, 0xff, 1); return 0; @@ -1482,7 +1482,7 @@ static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id * state->rgb_quantization_range_ctrl->is_private = true; state->pad.flags = MEDIA_PAD_FL_SINK; - err = media_entity_init(&sd->entity, 1, &state->pad, 0); + err = media_entity_pads_init(&sd->entity, 1, &state->pad); if (err) goto err_hdl; diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 01adcdc52..e1719ffdf 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -39,7 +39,7 @@ #include <linux/workqueue.h> #include <linux/regmap.h> -#include <media/adv7604.h> +#include <media/i2c/adv7604.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-event.h> @@ -905,7 +905,7 @@ static int find_and_set_predefined_video_timings(struct v4l2_subdev *sd, for (i = 0; predef_vid_timings[i].timings.bt.width; i++) { if (!v4l2_match_dv_timings(timings, &predef_vid_timings[i].timings, - is_digital_input(sd) ? 250000 : 1000000)) + is_digital_input(sd) ? 250000 : 1000000, false)) continue; io_write(sd, 0x00, predef_vid_timings[i].vid_std); /* video std */ io_write(sd, 0x01, (predef_vid_timings[i].v_freq << 4) + @@ -1479,7 +1479,7 @@ static void adv76xx_fill_optional_dv_timings_fields(struct v4l2_subdev *sd, for (i = 0; adv76xx_timings[i].bt.width; i++) { if (v4l2_match_dv_timings(timings, &adv76xx_timings[i], - is_digital_input(sd) ? 250000 : 1000000)) { + is_digital_input(sd) ? 250000 : 1000000, false)) { *timings = adv76xx_timings[i]; break; } @@ -1644,7 +1644,7 @@ static int adv76xx_s_dv_timings(struct v4l2_subdev *sd, if (!timings) return -EINVAL; - if (v4l2_match_dv_timings(&state->timings, timings, 0)) { + if (v4l2_match_dv_timings(&state->timings, timings, 0, false)) { v4l2_dbg(1, debug, sd, "%s: no change\n", __func__); return 0; } @@ -3207,8 +3207,8 @@ static int adv76xx_probe(struct i2c_client *client, state->pads[i].flags = MEDIA_PAD_FL_SINK; state->pads[state->source_pad].flags = MEDIA_PAD_FL_SOURCE; - err = media_entity_init(&sd->entity, state->source_pad + 1, - state->pads, 0); + err = media_entity_pads_init(&sd->entity, state->source_pad + 1, + state->pads); if (err) goto err_work_queues; diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index b7269b8f0..5fbb788e7 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c @@ -43,7 +43,7 @@ #include <media/v4l2-event.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-dv-timings.h> -#include <media/adv7842.h> +#include <media/i2c/adv7842.h> static int debug; module_param(debug, int, 0644); @@ -155,7 +155,7 @@ static bool adv7842_check_dv_timings(const struct v4l2_dv_timings *t, void *hdl) int i; for (i = 0; adv7842_timings_exceptions[i].bt.width; i++) - if (v4l2_match_dv_timings(t, adv7842_timings_exceptions + i, 0)) + if (v4l2_match_dv_timings(t, adv7842_timings_exceptions + i, 0, false)) return false; return true; } @@ -1008,7 +1008,7 @@ static int find_and_set_predefined_video_timings(struct v4l2_subdev *sd, for (i = 0; predef_vid_timings[i].timings.bt.width; i++) { if (!v4l2_match_dv_timings(timings, &predef_vid_timings[i].timings, - is_digital_input(sd) ? 250000 : 1000000)) + is_digital_input(sd) ? 250000 : 1000000, false)) continue; /* video std */ io_write(sd, 0x00, predef_vid_timings[i].vid_std); @@ -1659,7 +1659,7 @@ static int adv7842_s_dv_timings(struct v4l2_subdev *sd, if (state->mode == ADV7842_MODE_SDP) return -ENODATA; - if (v4l2_match_dv_timings(&state->timings, timings, 0)) { + if (v4l2_match_dv_timings(&state->timings, timings, 0, false)) { v4l2_dbg(1, debug, sd, "%s: no change\n", __func__); return 0; } @@ -3309,7 +3309,7 @@ static int adv7842_probe(struct i2c_client *client, adv7842_delayed_work_enable_hotplug); state->pad.flags = MEDIA_PAD_FL_SOURCE; - err = media_entity_init(&sd->entity, 1, &state->pad, 0); + err = media_entity_pads_init(&sd->entity, 1, &state->pad); if (err) goto err_work_queues; diff --git a/drivers/media/i2c/ak881x.c b/drivers/media/i2c/ak881x.c index d3b965ec3..d9f2b6b76 100644 --- a/drivers/media/i2c/ak881x.c +++ b/drivers/media/i2c/ak881x.c @@ -15,7 +15,7 @@ #include <linux/videodev2.h> #include <linux/module.h> -#include <media/ak881x.h> +#include <media/i2c/ak881x.h> #include <media/v4l2-common.h> #include <media/v4l2-device.h> diff --git a/drivers/media/i2c/as3645a.c b/drivers/media/i2c/as3645a.c index 301084b07..2e90e4094 100644 --- a/drivers/media/i2c/as3645a.c +++ b/drivers/media/i2c/as3645a.c @@ -31,7 +31,7 @@ #include <linux/mutex.h> #include <linux/slab.h> -#include <media/as3645a.h> +#include <media/i2c/as3645a.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> @@ -827,11 +827,11 @@ static int as3645a_probe(struct i2c_client *client, if (ret < 0) goto done; - ret = media_entity_init(&flash->subdev.entity, 0, NULL, 0); + ret = media_entity_pads_init(&flash->subdev.entity, 0, NULL); if (ret < 0) goto done; - flash->subdev.entity.type = MEDIA_ENT_T_V4L2_SUBDEV_FLASH; + flash->subdev.entity.function = MEDIA_ENT_F_FLASH; mutex_init(&flash->power_lock); diff --git a/drivers/media/i2c/bt819.c b/drivers/media/i2c/bt819.c index e00e3104d..7907bcfba 100644 --- a/drivers/media/i2c/bt819.c +++ b/drivers/media/i2c/bt819.c @@ -37,7 +37,7 @@ #include <linux/slab.h> #include <media/v4l2-device.h> #include <media/v4l2-ctrls.h> -#include <media/bt819.h> +#include <media/i2c/bt819.h> MODULE_DESCRIPTION("Brooktree-819 video decoder driver"); MODULE_AUTHOR("Mike Bernson & Dave Perks"); diff --git a/drivers/media/i2c/cs3308.c b/drivers/media/i2c/cs3308.c new file mode 100644 index 000000000..d28b4f37f --- /dev/null +++ b/drivers/media/i2c/cs3308.c @@ -0,0 +1,138 @@ +/* + * Cirrus Logic cs3308 8-Channel Analog Volume Control + * + * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com> + * Copyright (C) 2012 Steven Toth <stoth@kernellabs.com> + * + * Derived from cs5345.c Copyright (C) 2007 Hans Verkuil + * + * 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 + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/i2c.h> +#include <linux/slab.h> +#include <linux/videodev2.h> +#include <media/v4l2-device.h> + +MODULE_DESCRIPTION("i2c device driver for cs3308 8-channel volume control"); +MODULE_AUTHOR("Devin Heitmueller"); +MODULE_LICENSE("GPL"); + +static inline int cs3308_write(struct v4l2_subdev *sd, u8 reg, u8 value) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return i2c_smbus_write_byte_data(client, reg, value); +} + +static inline int cs3308_read(struct v4l2_subdev *sd, u8 reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return i2c_smbus_read_byte_data(client, reg); +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int cs3308_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) +{ + reg->val = cs3308_read(sd, reg->reg & 0xffff); + reg->size = 1; + return 0; +} + +static int cs3308_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) +{ + cs3308_write(sd, reg->reg & 0xffff, reg->val & 0xff); + return 0; +} +#endif + +/* ----------------------------------------------------------------------- */ + +static const struct v4l2_subdev_core_ops cs3308_core_ops = { +#ifdef CONFIG_VIDEO_ADV_DEBUG + .g_register = cs3308_g_register, + .s_register = cs3308_s_register, +#endif +}; + +static const struct v4l2_subdev_ops cs3308_ops = { + .core = &cs3308_core_ops, +}; + +/* ----------------------------------------------------------------------- */ + +static int cs3308_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct v4l2_subdev *sd; + unsigned i; + + /* Check if the adapter supports the needed features */ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; + + if ((i2c_smbus_read_byte_data(client, 0x1c) & 0xf0) != 0xe0) + return -ENODEV; + + v4l_info(client, "chip found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); + + sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL); + if (sd == NULL) + return -ENOMEM; + + v4l2_i2c_subdev_init(sd, client, &cs3308_ops); + + /* Set some reasonable defaults */ + cs3308_write(sd, 0x0d, 0x00); /* Power up all channels */ + cs3308_write(sd, 0x0e, 0x00); /* Master Power */ + cs3308_write(sd, 0x0b, 0x00); /* Device Configuration */ + /* Set volume for each channel */ + for (i = 1; i <= 8; i++) + cs3308_write(sd, i, 0xd2); + cs3308_write(sd, 0x0a, 0x00); /* Unmute all channels */ + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static int cs3308_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + + v4l2_device_unregister_subdev(sd); + kfree(sd); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static const struct i2c_device_id cs3308_id[] = { + { "cs3308", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, cs3308_id); + +static struct i2c_driver cs3308_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "cs3308", + }, + .probe = cs3308_probe, + .remove = cs3308_remove, + .id_table = cs3308_id, +}; + +module_i2c_driver(cs3308_driver); diff --git a/drivers/media/i2c/cx25840/cx25840-audio.c b/drivers/media/i2c/cx25840/cx25840-audio.c index 34b96c7cf..baf3d9c87 100644 --- a/drivers/media/i2c/cx25840/cx25840-audio.c +++ b/drivers/media/i2c/cx25840/cx25840-audio.c @@ -19,7 +19,7 @@ #include <linux/videodev2.h> #include <linux/i2c.h> #include <media/v4l2-common.h> -#include <media/cx25840.h> +#include <media/drv-intf/cx25840.h> #include "cx25840-core.h" diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c index fe6eb78b6..07a3e7173 100644 --- a/drivers/media/i2c/cx25840/cx25840-core.c +++ b/drivers/media/i2c/cx25840/cx25840-core.c @@ -45,7 +45,7 @@ #include <linux/delay.h> #include <linux/math64.h> #include <media/v4l2-common.h> -#include <media/cx25840.h> +#include <media/drv-intf/cx25840.h> #include "cx25840-core.h" @@ -559,7 +559,10 @@ static void cx23885_initialize(struct i2c_client *client) cx25840_write4(client, 0x414, 0x00107d12); /* Chroma */ - cx25840_write4(client, 0x420, 0x3d008282); + if (is_cx23888(state)) + cx25840_write4(client, 0x418, 0x1d008282); + else + cx25840_write4(client, 0x420, 0x3d008282); /* * Aux PLL @@ -666,14 +669,17 @@ static void cx23885_initialize(struct i2c_client *client) cx25840_write4(client, 0x404, 0x0010253e); /* CC on - Undocumented Register */ - cx25840_write(client, 0x42f, 0x66); + cx25840_write(client, state->vbi_regs_offset + 0x42f, 0x66); /* HVR-1250 / HVR1850 DIF related */ /* Power everything up */ cx25840_write4(client, 0x130, 0x0); /* Undocumented */ - cx25840_write4(client, 0x478, 0x6628021F); + if (is_cx23888(state)) + cx25840_write4(client, 0x454, 0x6628021F); + else + cx25840_write4(client, 0x478, 0x6628021F); /* AFE_CLK_OUT_CTRL - Select the clock output source as output */ cx25840_write4(client, 0x144, 0x5); @@ -1106,31 +1112,15 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp cx25840_write4(client, 0x410, 0xffff0dbf); cx25840_write4(client, 0x414, 0x00137d03); - /* on the 887, 0x418 is HSCALE_CTRL, on the 888 it is - CHROMA_CTRL */ - if (is_cx23888(state)) - cx25840_write4(client, 0x418, 0x01008080); - else - cx25840_write4(client, 0x418, 0x01000000); + cx25840_write4(client, state->vbi_regs_offset + 0x42c, 0x42600000); + cx25840_write4(client, state->vbi_regs_offset + 0x430, 0x0000039b); + cx25840_write4(client, state->vbi_regs_offset + 0x438, 0x00000000); - cx25840_write4(client, 0x41c, 0x00000000); - - /* on the 887, 0x420 is CHROMA_CTRL, on the 888 it is - CRUSH_CTRL */ - if (is_cx23888(state)) - cx25840_write4(client, 0x420, 0x001c3e0f); - else - cx25840_write4(client, 0x420, 0x001c8282); - - cx25840_write4(client, 0x42c, 0x42600000); - cx25840_write4(client, 0x430, 0x0000039b); - cx25840_write4(client, 0x438, 0x00000000); - - cx25840_write4(client, 0x440, 0xF8E3E824); - cx25840_write4(client, 0x444, 0x401040dc); - cx25840_write4(client, 0x448, 0xcd3f02a0); - cx25840_write4(client, 0x44c, 0x161f1000); - cx25840_write4(client, 0x450, 0x00000802); + cx25840_write4(client, state->vbi_regs_offset + 0x440, 0xF8E3E824); + cx25840_write4(client, state->vbi_regs_offset + 0x444, 0x401040dc); + cx25840_write4(client, state->vbi_regs_offset + 0x448, 0xcd3f02a0); + cx25840_write4(client, state->vbi_regs_offset + 0x44c, 0x161f1000); + cx25840_write4(client, state->vbi_regs_offset + 0x450, 0x00000802); cx25840_write4(client, 0x91c, 0x01000000); cx25840_write4(client, 0x8e0, 0x03063870); @@ -1400,8 +1390,14 @@ static int cx25840_set_fmt(struct v4l2_subdev *sd, Vlines = fmt->height + (is_50Hz ? 4 : 7); + /* + * We keep 1 margin for the Vsrc < Vlines check since the + * cx23888 reports a Vsrc of 486 instead of 487 for the NTSC + * height. Without that margin the cx23885 fails in this + * check. + */ if ((fmt->width * 16 < Hsrc) || (Hsrc < fmt->width) || - (Vlines * 8 < Vsrc) || (Vsrc < Vlines)) { + (Vlines * 8 < Vsrc) || (Vsrc + 1 < Vlines)) { v4l_err(client, "%dx%d is not a valid size!\n", fmt->width, fmt->height); return -ERANGE; @@ -1426,14 +1422,20 @@ static int cx25840_set_fmt(struct v4l2_subdev *sd, fmt->width, fmt->height, HSC, VSC); /* HSCALE=HSC */ - cx25840_write(client, 0x418, HSC & 0xff); - cx25840_write(client, 0x419, (HSC >> 8) & 0xff); - cx25840_write(client, 0x41a, HSC >> 16); - /* VSCALE=VSC */ - cx25840_write(client, 0x41c, VSC & 0xff); - cx25840_write(client, 0x41d, VSC >> 8); - /* VS_INTRLACE=1 VFILT=filter */ - cx25840_write(client, 0x41e, 0x8 | filter); + if (is_cx23888(state)) { + cx25840_write4(client, 0x434, HSC | (1 << 24)); + /* VSCALE=VSC VS_INTRLACE=1 VFILT=filter */ + cx25840_write4(client, 0x438, VSC | (1 << 19) | (filter << 16)); + } else { + cx25840_write(client, 0x418, HSC & 0xff); + cx25840_write(client, 0x419, (HSC >> 8) & 0xff); + cx25840_write(client, 0x41a, HSC >> 16); + /* VSCALE=VSC */ + cx25840_write(client, 0x41c, VSC & 0xff); + cx25840_write(client, 0x41d, VSC >> 8); + /* VS_INTRLACE=1 VFILT=filter */ + cx25840_write(client, 0x41e, 0x8 | filter); + } return 0; } @@ -1714,26 +1716,27 @@ static int cx25840_s_stream(struct v4l2_subdev *sd, int enable) v4l_dbg(1, cx25840_debug, client, "%s video output\n", enable ? "enable" : "disable"); + + /* + * It's not clear what should be done for these devices. + * The original code used the same addresses as for the cx25840, but + * those addresses do something else entirely on the cx2388x and + * cx231xx. Since it never did anything in the first place, just do + * nothing. + */ + if (is_cx2388x(state) || is_cx231xx(state)) + return 0; + if (enable) { - if (is_cx2388x(state) || is_cx231xx(state)) { - v = cx25840_read(client, 0x421) | 0x0b; - cx25840_write(client, 0x421, v); - } else { - v = cx25840_read(client, 0x115) | 0x0c; - cx25840_write(client, 0x115, v); - v = cx25840_read(client, 0x116) | 0x04; - cx25840_write(client, 0x116, v); - } + v = cx25840_read(client, 0x115) | 0x0c; + cx25840_write(client, 0x115, v); + v = cx25840_read(client, 0x116) | 0x04; + cx25840_write(client, 0x116, v); } else { - if (is_cx2388x(state) || is_cx231xx(state)) { - v = cx25840_read(client, 0x421) & ~(0x0b); - cx25840_write(client, 0x421, v); - } else { - v = cx25840_read(client, 0x115) & ~(0x0c); - cx25840_write(client, 0x115, v); - v = cx25840_read(client, 0x116) & ~(0x04); - cx25840_write(client, 0x116, v); - } + v = cx25840_read(client, 0x115) & ~(0x0c); + cx25840_write(client, 0x115, v); + v = cx25840_read(client, 0x116) & ~(0x04); + cx25840_write(client, 0x116, v); } return 0; } @@ -4974,7 +4977,7 @@ static void cx23888_std_setup(struct i2c_client *client) cx25840_write4(client, 0x4b4, 0x20524030); cx25840_write4(client, 0x47c, 0x010a8263); - if (std & V4L2_STD_NTSC) { + if (std & V4L2_STD_525_60) { v4l_dbg(1, cx25840_debug, client, "%s() Selecting NTSC", __func__); @@ -5208,10 +5211,10 @@ static int cx25840_probe(struct i2c_client *client, state->pads[CX25840_PAD_INPUT].flags = MEDIA_PAD_FL_SINK; state->pads[CX25840_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE; state->pads[CX25840_PAD_VBI_OUT].flags = MEDIA_PAD_FL_SOURCE; - sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_DECODER; + sd->entity.function = MEDIA_ENT_F_ATV_DECODER; - ret = media_entity_init(&sd->entity, ARRAY_SIZE(state->pads), - state->pads, 0); + ret = media_entity_pads_init(&sd->entity, ARRAY_SIZE(state->pads), + state->pads); if (ret < 0) { v4l_info(client, "failed to initialize media entity!\n"); return ret; @@ -5264,6 +5267,8 @@ static int cx25840_probe(struct i2c_client *client, state->vbi_line_offset = 8; state->id = id; state->rev = device_id; + state->vbi_regs_offset = id == CX23888_AV ? 0x500 - 0x424 : 0; + state->std = V4L2_STD_NTSC_M; v4l2_ctrl_handler_init(&state->hdl, 9); v4l2_ctrl_new_std(&state->hdl, &cx25840_ctrl_ops, V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); diff --git a/drivers/media/i2c/cx25840/cx25840-core.h b/drivers/media/i2c/cx25840/cx25840-core.h index fdea48ce0..254ef45ce 100644 --- a/drivers/media/i2c/cx25840/cx25840-core.h +++ b/drivers/media/i2c/cx25840/cx25840-core.h @@ -69,6 +69,7 @@ struct cx25840_state { enum cx25840_model id; u32 rev; int is_initialized; + unsigned vbi_regs_offset; wait_queue_head_t fw_wait; /* wake up when the fw load is finished */ struct work_struct fw_work; /* work entry for fw load */ struct cx25840_ir_state *ir_state; diff --git a/drivers/media/i2c/cx25840/cx25840-firmware.c b/drivers/media/i2c/cx25840/cx25840-firmware.c index b97d9709c..d0221e7a6 100644 --- a/drivers/media/i2c/cx25840/cx25840-firmware.c +++ b/drivers/media/i2c/cx25840/cx25840-firmware.c @@ -19,7 +19,7 @@ #include <linux/i2c.h> #include <linux/firmware.h> #include <media/v4l2-common.h> -#include <media/cx25840.h> +#include <media/drv-intf/cx25840.h> #include "cx25840-core.h" diff --git a/drivers/media/i2c/cx25840/cx25840-ir.c b/drivers/media/i2c/cx25840/cx25840-ir.c index 4cf8f18bf..4b782012c 100644 --- a/drivers/media/i2c/cx25840/cx25840-ir.c +++ b/drivers/media/i2c/cx25840/cx25840-ir.c @@ -24,7 +24,7 @@ #include <linux/slab.h> #include <linux/kfifo.h> #include <linux/module.h> -#include <media/cx25840.h> +#include <media/drv-intf/cx25840.h> #include <media/rc-core.h> #include "cx25840-core.h" diff --git a/drivers/media/i2c/cx25840/cx25840-vbi.c b/drivers/media/i2c/cx25840/cx25840-vbi.c index c39e91dc1..0470bb612 100644 --- a/drivers/media/i2c/cx25840/cx25840-vbi.c +++ b/drivers/media/i2c/cx25840/cx25840-vbi.c @@ -19,7 +19,7 @@ #include <linux/videodev2.h> #include <linux/i2c.h> #include <media/v4l2-common.h> -#include <media/cx25840.h> +#include <media/drv-intf/cx25840.h> #include "cx25840-core.h" @@ -104,7 +104,8 @@ int cx25840_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format * if (is_pal) { for (i = 7; i <= 23; i++) { - u8 v = cx25840_read(client, 0x424 + i - 7); + u8 v = cx25840_read(client, + state->vbi_regs_offset + 0x424 + i - 7); svbi->service_lines[0][i] = lcr2vbi[v >> 4]; svbi->service_lines[1][i] = lcr2vbi[v & 0xf]; @@ -113,7 +114,8 @@ int cx25840_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format * } } else { for (i = 10; i <= 21; i++) { - u8 v = cx25840_read(client, 0x424 + i - 10); + u8 v = cx25840_read(client, + state->vbi_regs_offset + 0x424 + i - 10); svbi->service_lines[0][i] = lcr2vbi[v >> 4]; svbi->service_lines[1][i] = lcr2vbi[v & 0xf]; @@ -135,7 +137,10 @@ int cx25840_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt) cx25840_std_setup(client); /* VBI Offset */ - cx25840_write(client, 0x47f, vbi_offset); + if (is_cx23888(state)) + cx25840_write(client, 0x54f, vbi_offset); + else + cx25840_write(client, 0x47f, vbi_offset); cx25840_write(client, 0x404, 0x2e); return 0; } @@ -158,7 +163,10 @@ int cx25840_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format * /* Sliced VBI */ cx25840_write(client, 0x404, 0x32); /* Ancillary data */ cx25840_write(client, 0x406, 0x13); - cx25840_write(client, 0x47f, vbi_offset); + if (is_cx23888(state)) + cx25840_write(client, 0x54f, vbi_offset); + else + cx25840_write(client, 0x47f, vbi_offset); if (is_pal) { for (i = 0; i <= 6; i++) @@ -194,17 +202,23 @@ int cx25840_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format * } if (is_pal) { - for (x = 1, i = 0x424; i <= 0x434; i++, x++) + for (x = 1, i = state->vbi_regs_offset + 0x424; + i <= state->vbi_regs_offset + 0x434; i++, x++) cx25840_write(client, i, lcr[6 + x]); } else { - for (x = 1, i = 0x424; i <= 0x430; i++, x++) + for (x = 1, i = state->vbi_regs_offset + 0x424; + i <= state->vbi_regs_offset + 0x430; i++, x++) cx25840_write(client, i, lcr[9 + x]); - for (i = 0x431; i <= 0x434; i++) + for (i = state->vbi_regs_offset + 0x431; + i <= state->vbi_regs_offset + 0x434; i++) cx25840_write(client, i, 0); } - cx25840_write(client, 0x43c, 0x16); - cx25840_write(client, 0x474, is_pal ? 0x2a : 0x22); + cx25840_write(client, state->vbi_regs_offset + 0x43c, 0x16); + if (is_cx23888(state)) + cx25840_write(client, 0x428, is_pal ? 0x2a : 0x22); + else + cx25840_write(client, 0x474, is_pal ? 0x2a : 0x22); return 0; } diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c index 175a76114..bf82726fd 100644 --- a/drivers/media/i2c/ir-kbd-i2c.c +++ b/drivers/media/i2c/ir-kbd-i2c.c @@ -47,7 +47,7 @@ #include <linux/workqueue.h> #include <media/rc-core.h> -#include <media/ir-kbd-i2c.h> +#include <media/i2c/ir-kbd-i2c.h> /* ----------------------------------------------------------------------- */ /* insmod parameters */ diff --git a/drivers/media/i2c/lm3560.c b/drivers/media/i2c/lm3560.c index d9ece4b2d..251a2aaf9 100644 --- a/drivers/media/i2c/lm3560.c +++ b/drivers/media/i2c/lm3560.c @@ -24,7 +24,7 @@ #include <linux/mutex.h> #include <linux/regmap.h> #include <linux/videodev2.h> -#include <media/lm3560.h> +#include <media/i2c/lm3560.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> @@ -365,10 +365,10 @@ static int lm3560_subdev_init(struct lm3560_flash *flash, rval = lm3560_init_controls(flash, led_no); if (rval) goto err_out; - rval = media_entity_init(&flash->subdev_led[led_no].entity, 0, NULL, 0); + rval = media_entity_pads_init(&flash->subdev_led[led_no].entity, 0, NULL); if (rval < 0) goto err_out; - flash->subdev_led[led_no].entity.type = MEDIA_ENT_T_V4L2_SUBDEV_FLASH; + flash->subdev_led[led_no].entity.function = MEDIA_ENT_F_FLASH; return rval; diff --git a/drivers/media/i2c/lm3646.c b/drivers/media/i2c/lm3646.c index 626fb4679..7e9967af3 100644 --- a/drivers/media/i2c/lm3646.c +++ b/drivers/media/i2c/lm3646.c @@ -18,7 +18,7 @@ #include <linux/slab.h> #include <linux/regmap.h> #include <linux/videodev2.h> -#include <media/lm3646.h> +#include <media/i2c/lm3646.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> @@ -282,10 +282,10 @@ static int lm3646_subdev_init(struct lm3646_flash *flash) rval = lm3646_init_controls(flash); if (rval) goto err_out; - rval = media_entity_init(&flash->subdev_led.entity, 0, NULL, 0); + rval = media_entity_pads_init(&flash->subdev_led.entity, 0, NULL); if (rval < 0) goto err_out; - flash->subdev_led.entity.type = MEDIA_ENT_T_V4L2_SUBDEV_FLASH; + flash->subdev_led.entity.function = MEDIA_ENT_F_FLASH; return rval; err_out: diff --git a/drivers/media/i2c/m52790.c b/drivers/media/i2c/m52790.c index 77eb07eb6..81171d8e1 100644 --- a/drivers/media/i2c/m52790.c +++ b/drivers/media/i2c/m52790.c @@ -27,7 +27,7 @@ #include <asm/uaccess.h> #include <linux/i2c.h> #include <linux/videodev2.h> -#include <media/m52790.h> +#include <media/i2c/m52790.h> #include <media/v4l2-device.h> MODULE_DESCRIPTION("i2c device driver for m52790 A/V switch"); diff --git a/drivers/media/i2c/m5mols/m5mols_capture.c b/drivers/media/i2c/m5mols/m5mols_capture.c index 1a03d02bd..a0cd6dc32 100644 --- a/drivers/media/i2c/m5mols/m5mols_capture.c +++ b/drivers/media/i2c/m5mols/m5mols_capture.c @@ -25,8 +25,8 @@ #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-subdev.h> -#include <media/m5mols.h> -#include <media/exynos-fimc.h> +#include <media/i2c/m5mols.h> +#include <media/drv-intf/exynos-fimc.h> #include "m5mols.h" #include "m5mols_reg.h" diff --git a/drivers/media/i2c/m5mols/m5mols_core.c b/drivers/media/i2c/m5mols/m5mols_core.c index 6404c0d93..acb804bce 100644 --- a/drivers/media/i2c/m5mols/m5mols_core.c +++ b/drivers/media/i2c/m5mols/m5mols_core.c @@ -25,7 +25,7 @@ #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-subdev.h> -#include <media/m5mols.h> +#include <media/i2c/m5mols.h> #include "m5mols.h" #include "m5mols_reg.h" @@ -975,10 +975,10 @@ static int m5mols_probe(struct i2c_client *client, sd->internal_ops = &m5mols_subdev_internal_ops; info->pad.flags = MEDIA_PAD_FL_SOURCE; - ret = media_entity_init(&sd->entity, 1, &info->pad, 0); + ret = media_entity_pads_init(&sd->entity, 1, &info->pad); if (ret < 0) return ret; - sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR; + sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; init_waitqueue_head(&info->irq_waitq); mutex_init(&info->lock); diff --git a/drivers/media/i2c/msp3400-driver.c b/drivers/media/i2c/msp3400-driver.c index bdb94000b..a84561d0d 100644 --- a/drivers/media/i2c/msp3400-driver.c +++ b/drivers/media/i2c/msp3400-driver.c @@ -56,8 +56,8 @@ #include <linux/videodev2.h> #include <media/v4l2-device.h> #include <media/v4l2-ioctl.h> -#include <media/msp3400.h> -#include <media/tvaudio.h> +#include <media/drv-intf/msp3400.h> +#include <media/i2c/tvaudio.h> #include "msp3400-driver.h" /* ---------------------------------------------------------------------- */ diff --git a/drivers/media/i2c/msp3400-driver.h b/drivers/media/i2c/msp3400-driver.h index fbe5e0715..6cae21366 100644 --- a/drivers/media/i2c/msp3400-driver.h +++ b/drivers/media/i2c/msp3400-driver.h @@ -4,7 +4,7 @@ #ifndef MSP3400_DRIVER_H #define MSP3400_DRIVER_H -#include <media/msp3400.h> +#include <media/drv-intf/msp3400.h> #include <media/v4l2-device.h> #include <media/v4l2-ctrls.h> diff --git a/drivers/media/i2c/msp3400-kthreads.c b/drivers/media/i2c/msp3400-kthreads.c index f8b51714f..17120804f 100644 --- a/drivers/media/i2c/msp3400-kthreads.c +++ b/drivers/media/i2c/msp3400-kthreads.c @@ -26,7 +26,7 @@ #include <linux/freezer.h> #include <linux/videodev2.h> #include <media/v4l2-common.h> -#include <media/msp3400.h> +#include <media/drv-intf/msp3400.h> #include <linux/kthread.h> #include <linux/suspend.h> #include "msp3400-driver.h" diff --git a/drivers/media/i2c/mt9m032.c b/drivers/media/i2c/mt9m032.c index c7747bd0c..da0767969 100644 --- a/drivers/media/i2c/mt9m032.c +++ b/drivers/media/i2c/mt9m032.c @@ -31,7 +31,7 @@ #include <linux/v4l2-mediabus.h> #include <media/media-entity.h> -#include <media/mt9m032.h> +#include <media/i2c/mt9m032.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-subdev.h> @@ -671,7 +671,7 @@ static int mt9m032_set_ctrl(struct v4l2_ctrl *ctrl) return 0; } -static struct v4l2_ctrl_ops mt9m032_ctrl_ops = { +static const struct v4l2_ctrl_ops mt9m032_ctrl_ops = { .s_ctrl = mt9m032_set_ctrl, .try_ctrl = mt9m032_try_ctrl, }; @@ -799,7 +799,7 @@ static int mt9m032_probe(struct i2c_client *client, sensor->subdev.ctrl_handler = &sensor->ctrls; sensor->pad.flags = MEDIA_PAD_FL_SOURCE; - ret = media_entity_init(&sensor->subdev.entity, 1, &sensor->pad, 0); + ret = media_entity_pads_init(&sensor->subdev.entity, 1, &sensor->pad); if (ret < 0) goto error_ctrl; diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c index 0db15f528..237737fec 100644 --- a/drivers/media/i2c/mt9p031.c +++ b/drivers/media/i2c/mt9p031.c @@ -26,7 +26,7 @@ #include <linux/slab.h> #include <linux/videodev2.h> -#include <media/mt9p031.h> +#include <media/i2c/mt9p031.h> #include <media/v4l2-async.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> @@ -817,7 +817,7 @@ static int mt9p031_s_ctrl(struct v4l2_ctrl *ctrl) return 0; } -static struct v4l2_ctrl_ops mt9p031_ctrl_ops = { +static const struct v4l2_ctrl_ops mt9p031_ctrl_ops = { .s_ctrl = mt9p031_s_ctrl, }; @@ -1112,7 +1112,7 @@ static int mt9p031_probe(struct i2c_client *client, mt9p031->subdev.internal_ops = &mt9p031_subdev_internal_ops; mt9p031->pad.flags = MEDIA_PAD_FL_SOURCE; - ret = media_entity_init(&mt9p031->subdev.entity, 1, &mt9p031->pad, 0); + ret = media_entity_pads_init(&mt9p031->subdev.entity, 1, &mt9p031->pad); if (ret < 0) goto done; diff --git a/drivers/media/i2c/mt9t001.c b/drivers/media/i2c/mt9t001.c index 8ae99f7f2..702d562f8 100644 --- a/drivers/media/i2c/mt9t001.c +++ b/drivers/media/i2c/mt9t001.c @@ -21,7 +21,7 @@ #include <linux/videodev2.h> #include <linux/v4l2-mediabus.h> -#include <media/mt9t001.h> +#include <media/i2c/mt9t001.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-subdev.h> @@ -626,7 +626,7 @@ static int mt9t001_s_ctrl(struct v4l2_ctrl *ctrl) return 0; } -static struct v4l2_ctrl_ops mt9t001_ctrl_ops = { +static const struct v4l2_ctrl_ops mt9t001_ctrl_ops = { .s_ctrl = mt9t001_s_ctrl, }; @@ -933,7 +933,7 @@ static int mt9t001_probe(struct i2c_client *client, mt9t001->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; mt9t001->pad.flags = MEDIA_PAD_FL_SOURCE; - ret = media_entity_init(&mt9t001->subdev.entity, 1, &mt9t001->pad, 0); + ret = media_entity_pads_init(&mt9t001->subdev.entity, 1, &mt9t001->pad); done: if (ret < 0) { diff --git a/drivers/media/i2c/mt9v011.c b/drivers/media/i2c/mt9v011.c index a4a5c39b5..b9fea11d6 100644 --- a/drivers/media/i2c/mt9v011.c +++ b/drivers/media/i2c/mt9v011.c @@ -13,7 +13,7 @@ #include <asm/div64.h> #include <media/v4l2-device.h> #include <media/v4l2-ctrls.h> -#include <media/mt9v011.h> +#include <media/i2c/mt9v011.h> MODULE_DESCRIPTION("Micron mt9v011 sensor driver"); MODULE_AUTHOR("Mauro Carvalho Chehab"); @@ -454,7 +454,7 @@ static int mt9v011_s_ctrl(struct v4l2_ctrl *ctrl) return 0; } -static struct v4l2_ctrl_ops mt9v011_ctrl_ops = { +static const struct v4l2_ctrl_ops mt9v011_ctrl_ops = { .s_ctrl = mt9v011_s_ctrl, }; diff --git a/drivers/media/i2c/mt9v032.c b/drivers/media/i2c/mt9v032.c index a68ce94ee..2e1d116a6 100644 --- a/drivers/media/i2c/mt9v032.c +++ b/drivers/media/i2c/mt9v032.c @@ -25,7 +25,7 @@ #include <linux/v4l2-mediabus.h> #include <linux/module.h> -#include <media/mt9v032.h> +#include <media/i2c/mt9v032.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-of.h> @@ -703,7 +703,7 @@ static int mt9v032_s_ctrl(struct v4l2_ctrl *ctrl) return 0; } -static struct v4l2_ctrl_ops mt9v032_ctrl_ops = { +static const struct v4l2_ctrl_ops mt9v032_ctrl_ops = { .s_ctrl = mt9v032_s_ctrl, }; @@ -1046,7 +1046,7 @@ static int mt9v032_probe(struct i2c_client *client, mt9v032->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; mt9v032->pad.flags = MEDIA_PAD_FL_SOURCE; - ret = media_entity_init(&mt9v032->subdev.entity, 1, &mt9v032->pad, 0); + ret = media_entity_pads_init(&mt9v032->subdev.entity, 1, &mt9v032->pad); if (ret < 0) goto err; diff --git a/drivers/media/i2c/noon010pc30.c b/drivers/media/i2c/noon010pc30.c index f197b6cbd..30cb90b88 100644 --- a/drivers/media/i2c/noon010pc30.c +++ b/drivers/media/i2c/noon010pc30.c @@ -18,7 +18,7 @@ #include <linux/i2c.h> #include <linux/slab.h> #include <linux/regulator/consumer.h> -#include <media/noon010pc30.h> +#include <media/i2c/noon010pc30.h> #include <linux/videodev2.h> #include <linux/module.h> #include <media/v4l2-ctrls.h> @@ -779,8 +779,8 @@ static int noon010_probe(struct i2c_client *client, goto np_err; info->pad.flags = MEDIA_PAD_FL_SOURCE; - sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR; - ret = media_entity_init(&sd->entity, 1, &info->pad, 0); + sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; + ret = media_entity_pads_init(&sd->entity, 1, &info->pad); if (ret < 0) goto np_err; diff --git a/drivers/media/i2c/ov2659.c b/drivers/media/i2c/ov2659.c index 49109f4f5..02b9a3440 100644 --- a/drivers/media/i2c/ov2659.c +++ b/drivers/media/i2c/ov2659.c @@ -37,7 +37,7 @@ #include <linux/videodev2.h> #include <media/media-entity.h> -#include <media/ov2659.h> +#include <media/i2c/ov2659.h> #include <media/v4l2-common.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> @@ -1249,7 +1249,7 @@ static int ov2659_s_ctrl(struct v4l2_ctrl *ctrl) return 0; } -static struct v4l2_ctrl_ops ov2659_ctrl_ops = { +static const struct v4l2_ctrl_ops ov2659_ctrl_ops = { .s_ctrl = ov2659_s_ctrl, }; @@ -1445,8 +1445,8 @@ static int ov2659_probe(struct i2c_client *client, #if defined(CONFIG_MEDIA_CONTROLLER) ov2659->pad.flags = MEDIA_PAD_FL_SOURCE; - sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR; - ret = media_entity_init(&sd->entity, 1, &ov2659->pad, 0); + sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; + ret = media_entity_pads_init(&sd->entity, 1, &ov2659->pad); if (ret < 0) { v4l2_ctrl_handler_free(&ov2659->ctrls); return ret; diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c index e1b5dc84c..56cfb5ca9 100644 --- a/drivers/media/i2c/ov7670.c +++ b/drivers/media/i2c/ov7670.c @@ -20,7 +20,7 @@ #include <media/v4l2-ctrls.h> #include <media/v4l2-mediabus.h> #include <media/v4l2-image-sizes.h> -#include <media/ov7670.h> +#include <media/i2c/ov7670.h> MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>"); MODULE_DESCRIPTION("A low-level driver for OmniVision ov7670 sensors"); diff --git a/drivers/media/i2c/ov9650.c b/drivers/media/i2c/ov9650.c index 1ee6a5527..a0b3c9bde 100644 --- a/drivers/media/i2c/ov9650.c +++ b/drivers/media/i2c/ov9650.c @@ -29,7 +29,7 @@ #include <media/v4l2-image-sizes.h> #include <media/v4l2-subdev.h> #include <media/v4l2-mediabus.h> -#include <media/ov9650.h> +#include <media/i2c/ov9650.h> static int debug; module_param(debug, int, 0644); @@ -1500,8 +1500,8 @@ static int ov965x_probe(struct i2c_client *client, return ret; ov965x->pad.flags = MEDIA_PAD_FL_SOURCE; - sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR; - ret = media_entity_init(&sd->entity, 1, &ov965x->pad, 0); + sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; + ret = media_entity_pads_init(&sd->entity, 1, &ov965x->pad); if (ret < 0) return ret; diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c index 7e7ccc179..9c89016ad 100644 --- a/drivers/media/i2c/s5c73m3/s5c73m3-core.c +++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c @@ -34,7 +34,7 @@ #include <media/v4l2-device.h> #include <media/v4l2-subdev.h> #include <media/v4l2-mediabus.h> -#include <media/s5c73m3.h> +#include <media/i2c/s5c73m3.h> #include <media/v4l2-of.h> #include "s5c73m3.h" @@ -1482,11 +1482,11 @@ static int s5c73m3_oif_registered(struct v4l2_subdev *sd) return ret; } - ret = media_entity_create_link(&state->sensor_sd.entity, + ret = media_create_pad_link(&state->sensor_sd.entity, S5C73M3_ISP_PAD, &state->oif_sd.entity, OIF_ISP_PAD, MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); - ret = media_entity_create_link(&state->sensor_sd.entity, + ret = media_create_pad_link(&state->sensor_sd.entity, S5C73M3_JPEG_PAD, &state->oif_sd.entity, OIF_JPEG_PAD, MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); @@ -1688,10 +1688,10 @@ static int s5c73m3_probe(struct i2c_client *client, state->sensor_pads[S5C73M3_JPEG_PAD].flags = MEDIA_PAD_FL_SOURCE; state->sensor_pads[S5C73M3_ISP_PAD].flags = MEDIA_PAD_FL_SOURCE; - sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV; + sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; - ret = media_entity_init(&sd->entity, S5C73M3_NUM_PADS, - state->sensor_pads, 0); + ret = media_entity_pads_init(&sd->entity, S5C73M3_NUM_PADS, + state->sensor_pads); if (ret < 0) return ret; @@ -1704,10 +1704,10 @@ static int s5c73m3_probe(struct i2c_client *client, state->oif_pads[OIF_ISP_PAD].flags = MEDIA_PAD_FL_SINK; state->oif_pads[OIF_JPEG_PAD].flags = MEDIA_PAD_FL_SINK; state->oif_pads[OIF_SOURCE_PAD].flags = MEDIA_PAD_FL_SOURCE; - oif_sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV; + oif_sd->entity.function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN; - ret = media_entity_init(&oif_sd->entity, OIF_NUM_PADS, - state->oif_pads, 0); + ret = media_entity_pads_init(&oif_sd->entity, OIF_NUM_PADS, + state->oif_pads); if (ret < 0) return ret; diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c b/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c index 8001cde1d..0a060339e 100644 --- a/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c +++ b/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c @@ -32,7 +32,7 @@ #include <media/v4l2-device.h> #include <media/v4l2-subdev.h> #include <media/v4l2-mediabus.h> -#include <media/s5c73m3.h> +#include <media/i2c/s5c73m3.h> #include "s5c73m3.h" diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-spi.c b/drivers/media/i2c/s5c73m3/s5c73m3-spi.c index 72ef9f936..7d65b3643 100644 --- a/drivers/media/i2c/s5c73m3/s5c73m3-spi.c +++ b/drivers/media/i2c/s5c73m3/s5c73m3-spi.c @@ -37,6 +37,7 @@ enum spi_direction { SPI_DIR_RX, SPI_DIR_TX }; +MODULE_DEVICE_TABLE(of, s5c73m3_spi_ids); static int spi_xmit(struct spi_device *spi_dev, void *addr, const int len, enum spi_direction dir) diff --git a/drivers/media/i2c/s5c73m3/s5c73m3.h b/drivers/media/i2c/s5c73m3/s5c73m3.h index 13aed59f0..653f68e7e 100644 --- a/drivers/media/i2c/s5c73m3/s5c73m3.h +++ b/drivers/media/i2c/s5c73m3/s5c73m3.h @@ -23,7 +23,7 @@ #include <media/v4l2-common.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-subdev.h> -#include <media/s5c73m3.h> +#include <media/i2c/s5c73m3.h> #define DRIVER_NAME "S5C73M3" diff --git a/drivers/media/i2c/s5k4ecgx.c b/drivers/media/i2c/s5k4ecgx.c index b5acf9584..c52f877e0 100644 --- a/drivers/media/i2c/s5k4ecgx.c +++ b/drivers/media/i2c/s5k4ecgx.c @@ -27,7 +27,7 @@ #include <asm/unaligned.h> #include <media/media-entity.h> -#include <media/s5k4ecgx.h> +#include <media/i2c/s5k4ecgx.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-mediabus.h> @@ -961,8 +961,8 @@ static int s5k4ecgx_probe(struct i2c_client *client, sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; priv->pad.flags = MEDIA_PAD_FL_SOURCE; - sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR; - ret = media_entity_init(&sd->entity, 1, &priv->pad, 0); + sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; + ret = media_entity_pads_init(&sd->entity, 1, &priv->pad); if (ret) return ret; diff --git a/drivers/media/i2c/s5k5baf.c b/drivers/media/i2c/s5k5baf.c index 5e8a3508d..5dfdb5d7e 100644 --- a/drivers/media/i2c/s5k5baf.c +++ b/drivers/media/i2c/s5k5baf.c @@ -408,7 +408,7 @@ static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl) static inline bool s5k5baf_is_cis_subdev(struct v4l2_subdev *sd) { - return sd->entity.type == MEDIA_ENT_T_V4L2_SUBDEV_SENSOR; + return sd->entity.function == MEDIA_ENT_F_CAM_SENSOR; } static inline struct s5k5baf *to_s5k5baf(struct v4l2_subdev *sd) @@ -1756,7 +1756,7 @@ static int s5k5baf_registered(struct v4l2_subdev *sd) v4l2_err(sd, "failed to register subdev %s\n", state->cis_sd.name); else - ret = media_entity_create_link(&state->cis_sd.entity, PAD_CIS, + ret = media_create_pad_link(&state->cis_sd.entity, PAD_CIS, &state->sd.entity, PAD_CIS, MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); @@ -1904,8 +1904,8 @@ static int s5k5baf_configure_subdevs(struct s5k5baf *state, sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; state->cis_pad.flags = MEDIA_PAD_FL_SOURCE; - sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR; - ret = media_entity_init(&sd->entity, NUM_CIS_PADS, &state->cis_pad, 0); + sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; + ret = media_entity_pads_init(&sd->entity, NUM_CIS_PADS, &state->cis_pad); if (ret < 0) goto err; @@ -1919,8 +1919,8 @@ static int s5k5baf_configure_subdevs(struct s5k5baf *state, state->pads[PAD_CIS].flags = MEDIA_PAD_FL_SINK; state->pads[PAD_OUT].flags = MEDIA_PAD_FL_SOURCE; - sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV; - ret = media_entity_init(&sd->entity, NUM_ISP_PADS, state->pads, 0); + sd->entity.function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN; + ret = media_entity_pads_init(&sd->entity, NUM_ISP_PADS, state->pads); if (!ret) return 0; diff --git a/drivers/media/i2c/s5k6a3.c b/drivers/media/i2c/s5k6a3.c index b1b1574df..cbe4711e9 100644 --- a/drivers/media/i2c/s5k6a3.c +++ b/drivers/media/i2c/s5k6a3.c @@ -144,8 +144,7 @@ static int s5k6a3_set_fmt(struct v4l2_subdev *sd, mf = __s5k6a3_get_format(sensor, cfg, fmt->pad, fmt->which); if (mf) { mutex_lock(&sensor->lock); - if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) - *mf = fmt->format; + *mf = fmt->format; mutex_unlock(&sensor->lock); } return 0; @@ -333,7 +332,7 @@ static int s5k6a3_probe(struct i2c_client *client, sensor->format.height = S5K6A3_DEFAULT_HEIGHT; sensor->pad.flags = MEDIA_PAD_FL_SOURCE; - ret = media_entity_init(&sd->entity, 1, &sensor->pad, 0); + ret = media_entity_pads_init(&sd->entity, 1, &sensor->pad); if (ret < 0) return ret; diff --git a/drivers/media/i2c/s5k6aa.c b/drivers/media/i2c/s5k6aa.c index d0ad6a25b..faee11383 100644 --- a/drivers/media/i2c/s5k6aa.c +++ b/drivers/media/i2c/s5k6aa.c @@ -28,7 +28,7 @@ #include <media/v4l2-device.h> #include <media/v4l2-subdev.h> #include <media/v4l2-mediabus.h> -#include <media/s5k6aa.h> +#include <media/i2c/s5k6aa.h> static int debug; module_param(debug, int, 0644); @@ -1577,8 +1577,8 @@ static int s5k6aa_probe(struct i2c_client *client, sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; s5k6aa->pad.flags = MEDIA_PAD_FL_SOURCE; - sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR; - ret = media_entity_init(&sd->entity, 1, &s5k6aa->pad, 0); + sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; + ret = media_entity_pads_init(&sd->entity, 1, &s5k6aa->pad); if (ret) return ret; diff --git a/drivers/media/i2c/saa6588.c b/drivers/media/i2c/saa6588.c index 37e65f661..89e458c23 100644 --- a/drivers/media/i2c/saa6588.c +++ b/drivers/media/i2c/saa6588.c @@ -31,7 +31,7 @@ #include <linux/wait.h> #include <asm/uaccess.h> -#include <media/saa6588.h> +#include <media/i2c/saa6588.h> #include <media/v4l2-device.h> diff --git a/drivers/media/i2c/saa7115.c b/drivers/media/i2c/saa7115.c index 91e75222c..24d2b76db 100644 --- a/drivers/media/i2c/saa7115.c +++ b/drivers/media/i2c/saa7115.c @@ -46,7 +46,7 @@ #include <linux/videodev2.h> #include <media/v4l2-device.h> #include <media/v4l2-ctrls.h> -#include <media/saa7115.h> +#include <media/i2c/saa7115.h> #include <asm/div64.h> #define VRES_60HZ (480+16) diff --git a/drivers/media/i2c/saa7127.c b/drivers/media/i2c/saa7127.c index a43d96da1..8d94dcbf4 100644 --- a/drivers/media/i2c/saa7127.c +++ b/drivers/media/i2c/saa7127.c @@ -54,7 +54,7 @@ #include <linux/i2c.h> #include <linux/videodev2.h> #include <media/v4l2-device.h> -#include <media/saa7127.h> +#include <media/i2c/saa7127.h> static int debug; static int test_image; diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index fb39dfd55..a215efe7a 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -2487,31 +2487,31 @@ static int smiapp_register_subdevs(struct smiapp_sensor *sensor) if (!last) continue; - rval = media_entity_init(&this->sd.entity, - this->npads, this->pads, 0); + rval = media_entity_pads_init(&this->sd.entity, + this->npads, this->pads); if (rval) { dev_err(&client->dev, - "media_entity_init failed\n"); + "media_entity_pads_init failed\n"); return rval; } - rval = media_entity_create_link(&this->sd.entity, - this->source_pad, - &last->sd.entity, - last->sink_pad, - MEDIA_LNK_FL_ENABLED | - MEDIA_LNK_FL_IMMUTABLE); + rval = v4l2_device_register_subdev(sensor->src->sd.v4l2_dev, + &this->sd); if (rval) { dev_err(&client->dev, - "media_entity_create_link failed\n"); + "v4l2_device_register_subdev failed\n"); return rval; } - rval = v4l2_device_register_subdev(sensor->src->sd.v4l2_dev, - &this->sd); + rval = media_create_pad_link(&this->sd.entity, + this->source_pad, + &last->sd.entity, + last->sink_pad, + MEDIA_LNK_FL_ENABLED | + MEDIA_LNK_FL_IMMUTABLE); if (rval) { dev_err(&client->dev, - "v4l2_device_register_subdev failed\n"); + "media_create_pad_link failed\n"); return rval; } } @@ -2763,7 +2763,7 @@ static int smiapp_init(struct smiapp_sensor *sensor) dev_dbg(&client->dev, "profile %d\n", sensor->minfo.smiapp_profile); - sensor->pixel_array->sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR; + sensor->pixel_array->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; /* final steps */ smiapp_read_frame_fmt(sensor); @@ -3077,8 +3077,8 @@ static int smiapp_probe(struct i2c_client *client, sensor->src->sensor = sensor; sensor->src->pads[0].flags = MEDIA_PAD_FL_SOURCE; - rval = media_entity_init(&sensor->src->sd.entity, 2, - sensor->src->pads, 0); + rval = media_entity_pads_init(&sensor->src->sd.entity, 2, + sensor->src->pads); if (rval < 0) return rval; diff --git a/drivers/media/i2c/smiapp/smiapp.h b/drivers/media/i2c/smiapp/smiapp.h index ed010a8a4..f6af0cc4a 100644 --- a/drivers/media/i2c/smiapp/smiapp.h +++ b/drivers/media/i2c/smiapp/smiapp.h @@ -22,7 +22,7 @@ #include <linux/mutex.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-subdev.h> -#include <media/smiapp.h> +#include <media/i2c/smiapp.h> #include "smiapp-pll.h" #include "smiapp-reg.h" diff --git a/drivers/media/i2c/soc_camera/mt9m001.c b/drivers/media/i2c/soc_camera/mt9m001.c index 4fbdd1e9f..2e14e52ba 100644 --- a/drivers/media/i2c/soc_camera/mt9m001.c +++ b/drivers/media/i2c/soc_camera/mt9m001.c @@ -15,7 +15,7 @@ #include <linux/module.h> #include <media/soc_camera.h> -#include <media/soc_mediabus.h> +#include <media/drv-intf/soc_mediabus.h> #include <media/v4l2-clk.h> #include <media/v4l2-subdev.h> #include <media/v4l2-ctrls.h> diff --git a/drivers/media/i2c/soc_camera/mt9t112.c b/drivers/media/i2c/soc_camera/mt9t112.c index 2f35d31ca..6a1b2a9f9 100644 --- a/drivers/media/i2c/soc_camera/mt9t112.c +++ b/drivers/media/i2c/soc_camera/mt9t112.c @@ -25,7 +25,7 @@ #include <linux/v4l2-mediabus.h> #include <linux/videodev2.h> -#include <media/mt9t112.h> +#include <media/i2c/mt9t112.h> #include <media/soc_camera.h> #include <media/v4l2-clk.h> #include <media/v4l2-common.h> diff --git a/drivers/media/i2c/soc_camera/mt9v022.c b/drivers/media/i2c/soc_camera/mt9v022.c index f31377408..c2ba1fb36 100644 --- a/drivers/media/i2c/soc_camera/mt9v022.c +++ b/drivers/media/i2c/soc_camera/mt9v022.c @@ -15,9 +15,9 @@ #include <linux/log2.h> #include <linux/module.h> -#include <media/mt9v022.h> +#include <media/i2c/mt9v022.h> #include <media/soc_camera.h> -#include <media/soc_mediabus.h> +#include <media/drv-intf/soc_mediabus.h> #include <media/v4l2-subdev.h> #include <media/v4l2-clk.h> #include <media/v4l2-ctrls.h> diff --git a/drivers/media/i2c/soc_camera/ov772x.c b/drivers/media/i2c/soc_camera/ov772x.c index f150a8bd9..a43410c1e 100644 --- a/drivers/media/i2c/soc_camera/ov772x.c +++ b/drivers/media/i2c/soc_camera/ov772x.c @@ -24,7 +24,7 @@ #include <linux/v4l2-mediabus.h> #include <linux/videodev2.h> -#include <media/ov772x.h> +#include <media/i2c/ov772x.h> #include <media/soc_camera.h> #include <media/v4l2-clk.h> #include <media/v4l2-ctrls.h> diff --git a/drivers/media/i2c/soc_camera/rj54n1cb0c.c b/drivers/media/i2c/soc_camera/rj54n1cb0c.c index c769cf663..aa7bfbb4a 100644 --- a/drivers/media/i2c/soc_camera/rj54n1cb0c.c +++ b/drivers/media/i2c/soc_camera/rj54n1cb0c.c @@ -15,7 +15,7 @@ #include <linux/videodev2.h> #include <linux/module.h> -#include <media/rj54n1cb0c.h> +#include <media/i2c/rj54n1cb0c.h> #include <media/soc_camera.h> #include <media/v4l2-clk.h> #include <media/v4l2-subdev.h> diff --git a/drivers/media/i2c/soc_camera/tw9910.c b/drivers/media/i2c/soc_camera/tw9910.c index e939c24bf..06aff8178 100644 --- a/drivers/media/i2c/soc_camera/tw9910.c +++ b/drivers/media/i2c/soc_camera/tw9910.c @@ -26,7 +26,7 @@ #include <linux/videodev2.h> #include <media/soc_camera.h> -#include <media/tw9910.h> +#include <media/i2c/tw9910.h> #include <media/v4l2-clk.h> #include <media/v4l2-subdev.h> diff --git a/drivers/media/i2c/sr030pc30.c b/drivers/media/i2c/sr030pc30.c index b04c09dd4..0bf031b7e 100644 --- a/drivers/media/i2c/sr030pc30.c +++ b/drivers/media/i2c/sr030pc30.c @@ -24,7 +24,7 @@ #include <media/v4l2-subdev.h> #include <media/v4l2-mediabus.h> #include <media/v4l2-ctrls.h> -#include <media/sr030pc30.h> +#include <media/i2c/sr030pc30.h> static int debug; module_param(debug, int, 0644); diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c index 9ef5baaf8..3397eb99c 100644 --- a/drivers/media/i2c/tc358743.c +++ b/drivers/media/i2c/tc358743.c @@ -42,7 +42,7 @@ #include <media/v4l2-ctrls.h> #include <media/v4l2-event.h> #include <media/v4l2-of.h> -#include <media/tc358743.h> +#include <media/i2c/tc358743.h> #include "tc358743_regs.h" @@ -862,7 +862,7 @@ static void tc358743_format_change(struct v4l2_subdev *sd) v4l2_dbg(1, debug, sd, "%s: Format changed. No signal\n", __func__); } else { - if (!v4l2_match_dv_timings(&state->timings, &timings, 0)) + if (!v4l2_match_dv_timings(&state->timings, &timings, 0, false)) enable_stream(sd, false); v4l2_print_dv_timings(sd->name, @@ -1366,7 +1366,7 @@ static int tc358743_s_dv_timings(struct v4l2_subdev *sd, v4l2_print_dv_timings(sd->name, "tc358743_s_dv_timings: ", timings, false); - if (v4l2_match_dv_timings(&state->timings, timings, 0)) { + if (v4l2_match_dv_timings(&state->timings, timings, 0, false)) { v4l2_dbg(1, debug, sd, "%s: no change\n", __func__); return 0; } @@ -1889,7 +1889,7 @@ static int tc358743_probe(struct i2c_client *client, } state->pad.flags = MEDIA_PAD_FL_SOURCE; - err = media_entity_init(&sd->entity, 1, &state->pad, 0); + err = media_entity_pads_init(&sd->entity, 1, &state->pad); if (err < 0) goto err_hdl; diff --git a/drivers/media/i2c/ths7303.c b/drivers/media/i2c/ths7303.c index bda3a6540..5bbfcab01 100644 --- a/drivers/media/i2c/ths7303.c +++ b/drivers/media/i2c/ths7303.c @@ -25,7 +25,7 @@ #include <linux/module.h> #include <linux/slab.h> -#include <media/ths7303.h> +#include <media/i2c/ths7303.h> #include <media/v4l2-device.h> #define THS7303_CHANNEL_1 1 diff --git a/drivers/media/i2c/tvaudio.c b/drivers/media/i2c/tvaudio.c index 2a8114a67..fece2a433 100644 --- a/drivers/media/i2c/tvaudio.c +++ b/drivers/media/i2c/tvaudio.c @@ -36,7 +36,7 @@ #include <linux/kthread.h> #include <linux/freezer.h> -#include <media/tvaudio.h> +#include <media/i2c/tvaudio.h> #include <media/v4l2-device.h> #include <media/v4l2-ctrls.h> diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c index a93985a9b..7fa5f1e4f 100644 --- a/drivers/media/i2c/tvp514x.c +++ b/drivers/media/i2c/tvp514x.c @@ -44,7 +44,7 @@ #include <media/v4l2-mediabus.h> #include <media/v4l2-of.h> #include <media/v4l2-ctrls.h> -#include <media/tvp514x.h> +#include <media/i2c/tvp514x.h> #include <media/media-entity.h> #include "tvp514x_regs.h" @@ -1095,9 +1095,9 @@ tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id) #if defined(CONFIG_MEDIA_CONTROLLER) decoder->pad.flags = MEDIA_PAD_FL_SOURCE; decoder->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - decoder->sd.entity.flags |= MEDIA_ENT_T_V4L2_SUBDEV_DECODER; + decoder->sd.entity.flags |= MEDIA_ENT_F_ATV_DECODER; - ret = media_entity_init(&decoder->sd.entity, 1, &decoder->pad, 0); + ret = media_entity_pads_init(&decoder->sd.entity, 1, &decoder->pad); if (ret < 0) { v4l2_err(sd, "%s decoder driver failed to register !!\n", sd->name); diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c index 3c5fb2509..6c3769d44 100644 --- a/drivers/media/i2c/tvp5150.c +++ b/drivers/media/i2c/tvp5150.c @@ -12,7 +12,7 @@ #include <linux/module.h> #include <media/v4l2-async.h> #include <media/v4l2-device.h> -#include <media/tvp5150.h> +#include <media/i2c/tvp5150.h> #include <media/v4l2-ctrls.h> #include "tvp5150_reg.h" diff --git a/drivers/media/i2c/tvp7002.c b/drivers/media/i2c/tvp7002.c index f617d8b74..83c79fa5f 100644 --- a/drivers/media/i2c/tvp7002.c +++ b/drivers/media/i2c/tvp7002.c @@ -32,7 +32,7 @@ #include <linux/of.h> #include <linux/of_graph.h> #include <linux/v4l2-dv-timings.h> -#include <media/tvp7002.h> +#include <media/i2c/tvp7002.h> #include <media/v4l2-async.h> #include <media/v4l2-device.h> #include <media/v4l2-common.h> @@ -1012,9 +1012,9 @@ static int tvp7002_probe(struct i2c_client *c, const struct i2c_device_id *id) #if defined(CONFIG_MEDIA_CONTROLLER) device->pad.flags = MEDIA_PAD_FL_SOURCE; device->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - device->sd.entity.flags |= MEDIA_ENT_T_V4L2_SUBDEV_DECODER; + device->sd.entity.flags |= MEDIA_ENT_F_ATV_DECODER; - error = media_entity_init(&device->sd.entity, 1, &device->pad, 0); + error = media_entity_pads_init(&device->sd.entity, 1, &device->pad); if (error < 0) return error; #endif diff --git a/drivers/media/i2c/uda1342.c b/drivers/media/i2c/uda1342.c index 081786d17..8e17a8392 100644 --- a/drivers/media/i2c/uda1342.c +++ b/drivers/media/i2c/uda1342.c @@ -20,7 +20,7 @@ #include <linux/i2c.h> #include <linux/videodev2.h> #include <media/v4l2-device.h> -#include <media/uda1342.h> +#include <media/i2c/uda1342.h> #include <linux/slab.h> static int write_reg(struct i2c_client *client, int reg, int value) diff --git a/drivers/media/i2c/upd64031a.c b/drivers/media/i2c/upd64031a.c index 2c0f955ab..c03567e99 100644 --- a/drivers/media/i2c/upd64031a.c +++ b/drivers/media/i2c/upd64031a.c @@ -27,7 +27,7 @@ #include <linux/videodev2.h> #include <linux/slab.h> #include <media/v4l2-device.h> -#include <media/upd64031a.h> +#include <media/i2c/upd64031a.h> /* --------------------- read registers functions define -------------------- */ diff --git a/drivers/media/i2c/upd64083.c b/drivers/media/i2c/upd64083.c index f2057a434..77f122f2e 100644 --- a/drivers/media/i2c/upd64083.c +++ b/drivers/media/i2c/upd64083.c @@ -27,7 +27,7 @@ #include <linux/videodev2.h> #include <linux/slab.h> #include <media/v4l2-device.h> -#include <media/upd64083.h> +#include <media/i2c/upd64083.h> MODULE_DESCRIPTION("uPD64083 driver"); MODULE_AUTHOR("T. Adachi, Takeru KOMORIYA, Hans Verkuil"); diff --git a/drivers/media/i2c/wm8775.c b/drivers/media/i2c/wm8775.c index d33d2cd6d..6e00f145b 100644 --- a/drivers/media/i2c/wm8775.c +++ b/drivers/media/i2c/wm8775.c @@ -34,7 +34,7 @@ #include <linux/videodev2.h> #include <media/v4l2-device.h> #include <media/v4l2-ctrls.h> -#include <media/wm8775.h> +#include <media/i2c/wm8775.h> MODULE_DESCRIPTION("wm8775 driver"); MODULE_AUTHOR("Ulf Eklund, Hans Verkuil"); diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c index 7b3944019..e9219f528 100644 --- a/drivers/media/media-device.c +++ b/drivers/media/media-device.c @@ -20,16 +20,23 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* We need to access legacy defines from linux/media.h */ +#define __NEED_MEDIA_LEGACY_API + #include <linux/compat.h> #include <linux/export.h> +#include <linux/idr.h> #include <linux/ioctl.h> #include <linux/media.h> +#include <linux/slab.h> #include <linux/types.h> #include <media/media-device.h> #include <media/media-devnode.h> #include <media/media-entity.h> +#ifdef CONFIG_MEDIA_CONTROLLER + /* ----------------------------------------------------------------------------- * Userspace API */ @@ -75,8 +82,8 @@ static struct media_entity *find_entity(struct media_device *mdev, u32 id) spin_lock(&mdev->lock); media_device_for_each_entity(entity, mdev) { - if ((entity->id == id && !next) || - (entity->id > id && next)) { + if (((media_entity_id(entity) == id) && !next) || + ((media_entity_id(entity) > id) && next)) { spin_unlock(&mdev->lock); return entity; } @@ -102,15 +109,35 @@ static long media_device_enum_entities(struct media_device *mdev, if (ent == NULL) return -EINVAL; - u_ent.id = ent->id; + u_ent.id = media_entity_id(ent); if (ent->name) strlcpy(u_ent.name, ent->name, sizeof(u_ent.name)); - u_ent.type = ent->type; - u_ent.revision = ent->revision; + u_ent.type = ent->function; + u_ent.revision = 0; /* Unused */ u_ent.flags = ent->flags; - u_ent.group_id = ent->group_id; + u_ent.group_id = 0; /* Unused */ u_ent.pads = ent->num_pads; u_ent.links = ent->num_links - ent->num_backlinks; + + /* + * Workaround for a bug at media-ctl <= v1.10 that makes it to + * do the wrong thing if the entity function doesn't belong to + * either MEDIA_ENT_F_OLD_BASE or MEDIA_ENT_F_OLD_SUBDEV_BASE + * Ranges. + * + * Non-subdevices are expected to be at the MEDIA_ENT_F_OLD_BASE, + * or, otherwise, will be silently ignored by media-ctl when + * printing the graphviz diagram. So, map them into the devnode + * old range. + */ + if (ent->function < MEDIA_ENT_F_OLD_BASE || + ent->function > MEDIA_ENT_T_DEVNODE_UNKNOWN) { + if (is_media_entity_v4l2_subdev(ent)) + u_ent.type = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN; + else if (ent->function != MEDIA_ENT_F_IO_V4L) + u_ent.type = MEDIA_ENT_T_DEVNODE_UNKNOWN; + } + memcpy(&u_ent.raw, &ent->info, sizeof(ent->info)); if (copy_to_user(uent, &u_ent, sizeof(u_ent))) return -EFAULT; @@ -120,7 +147,7 @@ static long media_device_enum_entities(struct media_device *mdev, static void media_device_kpad_to_upad(const struct media_pad *kpad, struct media_pad_desc *upad) { - upad->entity = kpad->entity->id; + upad->entity = media_entity_id(kpad->entity); upad->index = kpad->index; upad->flags = kpad->flags; } @@ -148,25 +175,25 @@ static long __media_device_enum_links(struct media_device *mdev, } if (links->links) { - struct media_link_desc __user *ulink; - unsigned int l; + struct media_link *link; + struct media_link_desc __user *ulink_desc = links->links; - for (l = 0, ulink = links->links; l < entity->num_links; l++) { - struct media_link_desc link; + list_for_each_entry(link, &entity->links, list) { + struct media_link_desc klink_desc; /* Ignore backlinks. */ - if (entity->links[l].source->entity != entity) + if (link->source->entity != entity) continue; - - memset(&link, 0, sizeof(link)); - media_device_kpad_to_upad(entity->links[l].source, - &link.source); - media_device_kpad_to_upad(entity->links[l].sink, - &link.sink); - link.flags = entity->links[l].flags; - if (copy_to_user(ulink, &link, sizeof(*ulink))) + memset(&klink_desc, 0, sizeof(klink_desc)); + media_device_kpad_to_upad(link->source, + &klink_desc.source); + media_device_kpad_to_upad(link->sink, + &klink_desc.sink); + klink_desc.flags = link->flags; + if (copy_to_user(ulink_desc, &klink_desc, + sizeof(*ulink_desc))) return -EFAULT; - ulink++; + ulink_desc++; } } @@ -230,6 +257,164 @@ static long media_device_setup_link(struct media_device *mdev, return ret; } +#if 0 /* Let's postpone it to Kernel 4.6 */ +static long __media_device_get_topology(struct media_device *mdev, + struct media_v2_topology *topo) +{ + struct media_entity *entity; + struct media_interface *intf; + struct media_pad *pad; + struct media_link *link; + struct media_v2_entity kentity, *uentity; + struct media_v2_interface kintf, *uintf; + struct media_v2_pad kpad, *upad; + struct media_v2_link klink, *ulink; + unsigned int i; + int ret = 0; + + topo->topology_version = mdev->topology_version; + + /* Get entities and number of entities */ + i = 0; + uentity = media_get_uptr(topo->ptr_entities); + media_device_for_each_entity(entity, mdev) { + i++; + if (ret || !uentity) + continue; + + if (i > topo->num_entities) { + ret = -ENOSPC; + continue; + } + + /* Copy fields to userspace struct if not error */ + memset(&kentity, 0, sizeof(kentity)); + kentity.id = entity->graph_obj.id; + kentity.function = entity->function; + strncpy(kentity.name, entity->name, + sizeof(kentity.name)); + + if (copy_to_user(uentity, &kentity, sizeof(kentity))) + ret = -EFAULT; + uentity++; + } + topo->num_entities = i; + + /* Get interfaces and number of interfaces */ + i = 0; + uintf = media_get_uptr(topo->ptr_interfaces); + media_device_for_each_intf(intf, mdev) { + i++; + if (ret || !uintf) + continue; + + if (i > topo->num_interfaces) { + ret = -ENOSPC; + continue; + } + + memset(&kintf, 0, sizeof(kintf)); + + /* Copy intf fields to userspace struct */ + kintf.id = intf->graph_obj.id; + kintf.intf_type = intf->type; + kintf.flags = intf->flags; + + if (media_type(&intf->graph_obj) == MEDIA_GRAPH_INTF_DEVNODE) { + struct media_intf_devnode *devnode; + + devnode = intf_to_devnode(intf); + + kintf.devnode.major = devnode->major; + kintf.devnode.minor = devnode->minor; + } + + if (copy_to_user(uintf, &kintf, sizeof(kintf))) + ret = -EFAULT; + uintf++; + } + topo->num_interfaces = i; + + /* Get pads and number of pads */ + i = 0; + upad = media_get_uptr(topo->ptr_pads); + media_device_for_each_pad(pad, mdev) { + i++; + if (ret || !upad) + continue; + + if (i > topo->num_pads) { + ret = -ENOSPC; + continue; + } + + memset(&kpad, 0, sizeof(kpad)); + + /* Copy pad fields to userspace struct */ + kpad.id = pad->graph_obj.id; + kpad.entity_id = pad->entity->graph_obj.id; + kpad.flags = pad->flags; + + if (copy_to_user(upad, &kpad, sizeof(kpad))) + ret = -EFAULT; + upad++; + } + topo->num_pads = i; + + /* Get links and number of links */ + i = 0; + ulink = media_get_uptr(topo->ptr_links); + media_device_for_each_link(link, mdev) { + if (link->is_backlink) + continue; + + i++; + + if (ret || !ulink) + continue; + + if (i > topo->num_links) { + ret = -ENOSPC; + continue; + } + + memset(&klink, 0, sizeof(klink)); + + /* Copy link fields to userspace struct */ + klink.id = link->graph_obj.id; + klink.source_id = link->gobj0->id; + klink.sink_id = link->gobj1->id; + klink.flags = link->flags; + + if (copy_to_user(ulink, &klink, sizeof(klink))) + ret = -EFAULT; + ulink++; + } + topo->num_links = i; + + return ret; +} + +static long media_device_get_topology(struct media_device *mdev, + struct media_v2_topology __user *utopo) +{ + struct media_v2_topology ktopo; + int ret; + + if (copy_from_user(&ktopo, utopo, sizeof(ktopo))) + return -EFAULT; + + ret = __media_device_get_topology(mdev, &ktopo); + if (ret < 0) + return ret; + + if (copy_to_user(utopo, &ktopo, sizeof(*utopo))) + return -EFAULT; + + return 0; +} +#endif + static long media_device_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { @@ -262,6 +447,14 @@ static long media_device_ioctl(struct file *filp, unsigned int cmd, mutex_unlock(&dev->graph_mutex); break; +#if 0 /* Let's postpone it to Kernel 4.6 */ + case MEDIA_IOC_G_TOPOLOGY: + mutex_lock(&dev->graph_mutex); + ret = media_device_get_topology(dev, + (struct media_v2_topology __user *)arg); + mutex_unlock(&dev->graph_mutex); + break; +#endif default: ret = -ENOIOCTLCMD; } @@ -310,6 +503,9 @@ static long media_device_compat_ioctl(struct file *filp, unsigned int cmd, case MEDIA_IOC_DEVICE_INFO: case MEDIA_IOC_ENUM_ENTITIES: case MEDIA_IOC_SETUP_LINK: +#if 0 /* Let's postpone it to Kernel 4.6 */ + case MEDIA_IOC_G_TOPOLOGY: +#endif return media_device_ioctl(filp, cmd, arg); case MEDIA_IOC_ENUM_LINKS32: @@ -357,10 +553,107 @@ static DEVICE_ATTR(model, S_IRUGO, show_model, NULL); static void media_device_release(struct media_devnode *mdev) { + dev_dbg(mdev->parent, "Media device released\n"); } /** - * media_device_register - register a media device + * media_device_register_entity - Register an entity with a media device + * @mdev: The media device + * @entity: The entity + */ +int __must_check media_device_register_entity(struct media_device *mdev, + struct media_entity *entity) +{ + unsigned int i; + int ret; + + if (entity->function == MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN || + entity->function == MEDIA_ENT_F_UNKNOWN) + dev_warn(mdev->dev, + "Entity type for entity %s was not initialized!\n", + entity->name); + + /* Warn if we apparently re-register an entity */ + WARN_ON(entity->graph_obj.mdev != NULL); + entity->graph_obj.mdev = mdev; + INIT_LIST_HEAD(&entity->links); + entity->num_links = 0; + entity->num_backlinks = 0; + + if (!ida_pre_get(&mdev->entity_internal_idx, GFP_KERNEL)) + return -ENOMEM; + + spin_lock(&mdev->lock); + + ret = ida_get_new_above(&mdev->entity_internal_idx, 1, + &entity->internal_idx); + if (ret < 0) { + spin_unlock(&mdev->lock); + return ret; + } + + mdev->entity_internal_idx_max = + max(mdev->entity_internal_idx_max, entity->internal_idx); + + /* Initialize media_gobj embedded at the entity */ + media_gobj_create(mdev, MEDIA_GRAPH_ENTITY, &entity->graph_obj); + + /* Initialize objects at the pads */ + for (i = 0; i < entity->num_pads; i++) + media_gobj_create(mdev, MEDIA_GRAPH_PAD, + &entity->pads[i].graph_obj); + + spin_unlock(&mdev->lock); + + return 0; +} +EXPORT_SYMBOL_GPL(media_device_register_entity); + +static void __media_device_unregister_entity(struct media_entity *entity) +{ + struct media_device *mdev = entity->graph_obj.mdev; + struct media_link *link, *tmp; + struct media_interface *intf; + unsigned int i; + + ida_simple_remove(&mdev->entity_internal_idx, entity->internal_idx); + + /* Remove all interface links pointing to this entity */ + list_for_each_entry(intf, &mdev->interfaces, graph_obj.list) { + list_for_each_entry_safe(link, tmp, &intf->links, list) { + if (link->entity == entity) + __media_remove_intf_link(link); + } + } + + /* Remove all data links that belong to this entity */ + __media_entity_remove_links(entity); + + /* Remove all pads that belong to this entity */ + for (i = 0; i < entity->num_pads; i++) + media_gobj_destroy(&entity->pads[i].graph_obj); + + /* Remove the entity */ + media_gobj_destroy(&entity->graph_obj); + + entity->graph_obj.mdev = NULL; +} + +void media_device_unregister_entity(struct media_entity *entity) +{ + struct media_device *mdev = entity->graph_obj.mdev; + + if (mdev == NULL) + return; + + spin_lock(&mdev->lock); + __media_device_unregister_entity(entity); + spin_unlock(&mdev->lock); +} +EXPORT_SYMBOL_GPL(media_device_unregister_entity); + +/** + * media_device_init() - initialize a media device * @mdev: The media device * * The caller is responsible for initializing the media device before @@ -369,23 +662,41 @@ static void media_device_release(struct media_devnode *mdev) * - dev must point to the parent device * - model must be filled with the device model name */ -int __must_check __media_device_register(struct media_device *mdev, - struct module *owner) +void media_device_init(struct media_device *mdev) { - int ret; - - if (WARN_ON(mdev->dev == NULL || mdev->model[0] == 0)) - return -EINVAL; - - mdev->entity_id = 1; INIT_LIST_HEAD(&mdev->entities); + INIT_LIST_HEAD(&mdev->interfaces); + INIT_LIST_HEAD(&mdev->pads); + INIT_LIST_HEAD(&mdev->links); spin_lock_init(&mdev->lock); mutex_init(&mdev->graph_mutex); + ida_init(&mdev->entity_internal_idx); + + dev_dbg(mdev->dev, "Media device initialized\n"); +} +EXPORT_SYMBOL_GPL(media_device_init); + +void media_device_cleanup(struct media_device *mdev) +{ + ida_destroy(&mdev->entity_internal_idx); + mdev->entity_internal_idx_max = 0; + mutex_destroy(&mdev->graph_mutex); +} +EXPORT_SYMBOL_GPL(media_device_cleanup); + +int __must_check __media_device_register(struct media_device *mdev, + struct module *owner) +{ + int ret; /* Register the device node. */ mdev->devnode.fops = &media_device_fops; mdev->devnode.parent = mdev->dev; mdev->devnode.release = media_device_release; + + /* Set version 0 to indicate user-space that the graph is static */ + mdev->topology_version = 0; + ret = media_devnode_register(&mdev->devnode, owner); if (ret < 0) return ret; @@ -396,69 +707,74 @@ int __must_check __media_device_register(struct media_device *mdev, return ret; } + dev_dbg(mdev->dev, "Media device registered\n"); + return 0; } EXPORT_SYMBOL_GPL(__media_device_register); -/** - * media_device_unregister - unregister a media device - * @mdev: The media device - * - */ void media_device_unregister(struct media_device *mdev) { struct media_entity *entity; struct media_entity *next; + struct media_interface *intf, *tmp_intf; + + if (mdev == NULL) + return; + + spin_lock(&mdev->lock); - list_for_each_entry_safe(entity, next, &mdev->entities, list) - media_device_unregister_entity(entity); + /* Check if mdev was ever registered at all */ + if (!media_devnode_is_registered(&mdev->devnode)) { + spin_unlock(&mdev->lock); + return; + } + + /* Remove all entities from the media device */ + list_for_each_entry_safe(entity, next, &mdev->entities, graph_obj.list) + __media_device_unregister_entity(entity); + + /* Remove all interfaces from the media device */ + list_for_each_entry_safe(intf, tmp_intf, &mdev->interfaces, + graph_obj.list) { + __media_remove_intf_links(intf); + media_gobj_destroy(&intf->graph_obj); + kfree(intf); + } + + spin_unlock(&mdev->lock); device_remove_file(&mdev->devnode.dev, &dev_attr_model); media_devnode_unregister(&mdev->devnode); + + dev_dbg(mdev->dev, "Media device unregistered\n"); } EXPORT_SYMBOL_GPL(media_device_unregister); -/** - * media_device_register_entity - Register an entity with a media device - * @mdev: The media device - * @entity: The entity - */ -int __must_check media_device_register_entity(struct media_device *mdev, - struct media_entity *entity) +static void media_device_release_devres(struct device *dev, void *res) { - /* Warn if we apparently re-register an entity */ - WARN_ON(entity->parent != NULL); - entity->parent = mdev; - - spin_lock(&mdev->lock); - if (entity->id == 0) - entity->id = mdev->entity_id++; - else - mdev->entity_id = max(entity->id + 1, mdev->entity_id); - list_add_tail(&entity->list, &mdev->entities); - spin_unlock(&mdev->lock); - - return 0; } -EXPORT_SYMBOL_GPL(media_device_register_entity); -/** - * media_device_unregister_entity - Unregister an entity - * @entity: The entity - * - * If the entity has never been registered this function will return - * immediately. - */ -void media_device_unregister_entity(struct media_entity *entity) +struct media_device *media_device_get_devres(struct device *dev) { - struct media_device *mdev = entity->parent; + struct media_device *mdev; - if (mdev == NULL) - return; + mdev = devres_find(dev, media_device_release_devres, NULL, NULL); + if (mdev) + return mdev; - spin_lock(&mdev->lock); - list_del(&entity->list); - spin_unlock(&mdev->lock); - entity->parent = NULL; + mdev = devres_alloc(media_device_release_devres, + sizeof(struct media_device), GFP_KERNEL); + if (!mdev) + return NULL; + return devres_get(dev, mdev, NULL, NULL); } -EXPORT_SYMBOL_GPL(media_device_unregister_entity); +EXPORT_SYMBOL_GPL(media_device_get_devres); + +struct media_device *media_device_find_devres(struct device *dev) +{ + return devres_find(dev, media_device_release_devres, NULL, NULL); +} +EXPORT_SYMBOL_GPL(media_device_find_devres); + +#endif /* CONFIG_MEDIA_CONTROLLER */ diff --git a/drivers/media/media-devnode.c b/drivers/media/media-devnode.c index ebf9626e5..cea35bf20 100644 --- a/drivers/media/media-devnode.c +++ b/drivers/media/media-devnode.c @@ -217,20 +217,6 @@ static const struct file_operations media_devnode_fops = { .llseek = no_llseek, }; -/** - * media_devnode_register - register a media device node - * @mdev: media device node structure we want to register - * - * The registration code assigns minor numbers and registers the new device node - * with the kernel. An error is returned if no free minor number can be found, - * or if the registration of the device node fails. - * - * Zero is returned on success. - * - * Note that if the media_devnode_register call fails, the release() callback of - * the media_devnode structure is *not* called, so the caller is responsible for - * freeing any data. - */ int __must_check media_devnode_register(struct media_devnode *mdev, struct module *owner) { @@ -285,16 +271,6 @@ error: return ret; } -/** - * media_devnode_unregister - unregister a media device node - * @mdev: the device node to unregister - * - * This unregisters the passed device. Future open calls will be met with - * errors. - * - * This function can safely be called if the device node has never been - * registered or has already been unregistered. - */ void media_devnode_unregister(struct media_devnode *mdev) { /* Check if mdev was ever registered at all */ diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c index 767fe55ba..e89d85a7d 100644 --- a/drivers/media/media-entity.c +++ b/drivers/media/media-entity.c @@ -26,65 +26,198 @@ #include <media/media-entity.h> #include <media/media-device.h> +static inline const char *gobj_type(enum media_gobj_type type) +{ + switch (type) { + case MEDIA_GRAPH_ENTITY: + return "entity"; + case MEDIA_GRAPH_PAD: + return "pad"; + case MEDIA_GRAPH_LINK: + return "link"; + case MEDIA_GRAPH_INTF_DEVNODE: + return "intf-devnode"; + default: + return "unknown"; + } +} + +static inline const char *intf_type(struct media_interface *intf) +{ + switch (intf->type) { + case MEDIA_INTF_T_DVB_FE: + return "frontend"; + case MEDIA_INTF_T_DVB_DEMUX: + return "demux"; + case MEDIA_INTF_T_DVB_DVR: + return "DVR"; + case MEDIA_INTF_T_DVB_CA: + return "CA"; + case MEDIA_INTF_T_DVB_NET: + return "dvbnet"; + case MEDIA_INTF_T_V4L_VIDEO: + return "video"; + case MEDIA_INTF_T_V4L_VBI: + return "vbi"; + case MEDIA_INTF_T_V4L_RADIO: + return "radio"; + case MEDIA_INTF_T_V4L_SUBDEV: + return "v4l2-subdev"; + case MEDIA_INTF_T_V4L_SWRADIO: + return "swradio"; + default: + return "unknown-intf"; + } +}; + +__must_check int __media_entity_enum_init(struct media_entity_enum *ent_enum, + int idx_max) +{ + ent_enum->bmap = kcalloc(DIV_ROUND_UP(idx_max, BITS_PER_LONG), + sizeof(long), GFP_KERNEL); + if (!ent_enum->bmap) + return -ENOMEM; + + bitmap_zero(ent_enum->bmap, idx_max); + ent_enum->idx_max = idx_max; + + return 0; +} +EXPORT_SYMBOL_GPL(__media_entity_enum_init); + +void media_entity_enum_cleanup(struct media_entity_enum *ent_enum) +{ + kfree(ent_enum->bmap); +} +EXPORT_SYMBOL_GPL(media_entity_enum_cleanup); + /** - * media_entity_init - Initialize a media entity - * - * @num_pads: Total number of sink and source pads. - * @extra_links: Initial estimate of the number of extra links. - * @pads: Array of 'num_pads' pads. - * - * The total number of pads is an intrinsic property of entities known by the - * entity driver, while the total number of links depends on hardware design - * and is an extrinsic property unknown to the entity driver. However, in most - * use cases the entity driver can guess the number of links which can safely - * be assumed to be equal to or larger than the number of pads. - * - * For those reasons the links array can be preallocated based on the entity - * driver guess and will be reallocated later if extra links need to be - * created. + * dev_dbg_obj - Prints in debug mode a change on some object * - * This function allocates a links array with enough space to hold at least - * 'num_pads' + 'extra_links' elements. The media_entity::max_links field will - * be set to the number of allocated elements. + * @event_name: Name of the event to report. Could be __func__ + * @gobj: Pointer to the object * - * The pads array is managed by the entity driver and passed to - * media_entity_init() where its pointer will be stored in the entity structure. + * Enabled only if DEBUG or CONFIG_DYNAMIC_DEBUG. Otherwise, it + * won't produce any code. */ -int -media_entity_init(struct media_entity *entity, u16 num_pads, - struct media_pad *pads, u16 extra_links) +static void dev_dbg_obj(const char *event_name, struct media_gobj *gobj) { - struct media_link *links; - unsigned int max_links = num_pads + extra_links; - unsigned int i; +#if defined(DEBUG) || defined (CONFIG_DYNAMIC_DEBUG) + switch (media_type(gobj)) { + case MEDIA_GRAPH_ENTITY: + dev_dbg(gobj->mdev->dev, + "%s id %u: entity '%s'\n", + event_name, media_id(gobj), + gobj_to_entity(gobj)->name); + break; + case MEDIA_GRAPH_LINK: + { + struct media_link *link = gobj_to_link(gobj); + + dev_dbg(gobj->mdev->dev, + "%s id %u: %s link id %u ==> id %u\n", + event_name, media_id(gobj), + media_type(link->gobj0) == MEDIA_GRAPH_PAD ? + "data" : "interface", + media_id(link->gobj0), + media_id(link->gobj1)); + break; + } + case MEDIA_GRAPH_PAD: + { + struct media_pad *pad = gobj_to_pad(gobj); + + dev_dbg(gobj->mdev->dev, + "%s id %u: %s%spad '%s':%d\n", + event_name, media_id(gobj), + pad->flags & MEDIA_PAD_FL_SINK ? "sink " : "", + pad->flags & MEDIA_PAD_FL_SOURCE ? "source " : "", + pad->entity->name, pad->index); + break; + } + case MEDIA_GRAPH_INTF_DEVNODE: + { + struct media_interface *intf = gobj_to_intf(gobj); + struct media_intf_devnode *devnode = intf_to_devnode(intf); + + dev_dbg(gobj->mdev->dev, + "%s id %u: intf_devnode %s - major: %d, minor: %d\n", + event_name, media_id(gobj), + intf_type(intf), + devnode->major, devnode->minor); + break; + } + } +#endif +} - links = kzalloc(max_links * sizeof(links[0]), GFP_KERNEL); - if (links == NULL) - return -ENOMEM; +void media_gobj_create(struct media_device *mdev, + enum media_gobj_type type, + struct media_gobj *gobj) +{ + BUG_ON(!mdev); + + gobj->mdev = mdev; + + /* Create a per-type unique object ID */ + gobj->id = media_gobj_gen_id(type, ++mdev->id); + + switch (type) { + case MEDIA_GRAPH_ENTITY: + list_add_tail(&gobj->list, &mdev->entities); + break; + case MEDIA_GRAPH_PAD: + list_add_tail(&gobj->list, &mdev->pads); + break; + case MEDIA_GRAPH_LINK: + list_add_tail(&gobj->list, &mdev->links); + break; + case MEDIA_GRAPH_INTF_DEVNODE: + list_add_tail(&gobj->list, &mdev->interfaces); + break; + } + + mdev->topology_version++; + + dev_dbg_obj(__func__, gobj); +} + +void media_gobj_destroy(struct media_gobj *gobj) +{ + dev_dbg_obj(__func__, gobj); + + gobj->mdev->topology_version++; + + /* Remove the object from mdev list */ + list_del(&gobj->list); +} + +int media_entity_pads_init(struct media_entity *entity, u16 num_pads, + struct media_pad *pads) +{ + struct media_device *mdev = entity->graph_obj.mdev; + unsigned int i; - entity->group_id = 0; - entity->max_links = max_links; - entity->num_links = 0; - entity->num_backlinks = 0; entity->num_pads = num_pads; entity->pads = pads; - entity->links = links; + + if (mdev) + spin_lock(&mdev->lock); for (i = 0; i < num_pads; i++) { pads[i].entity = entity; pads[i].index = i; + if (mdev) + media_gobj_create(mdev, MEDIA_GRAPH_PAD, + &entity->pads[i].graph_obj); } - return 0; -} -EXPORT_SYMBOL_GPL(media_entity_init); + if (mdev) + spin_unlock(&mdev->lock); -void -media_entity_cleanup(struct media_entity *entity) -{ - kfree(entity->links); + return 0; } -EXPORT_SYMBOL_GPL(media_entity_cleanup); +EXPORT_SYMBOL_GPL(media_entity_pads_init); /* ----------------------------------------------------------------------------- * Graph traversal @@ -108,7 +241,7 @@ static void stack_push(struct media_entity_graph *graph, return; } graph->top++; - graph->stack[graph->top].link = 0; + graph->stack[graph->top].link = entity->links.next; graph->stack[graph->top].entity = entity; } @@ -125,43 +258,51 @@ static struct media_entity *stack_pop(struct media_entity_graph *graph) #define link_top(en) ((en)->stack[(en)->top].link) #define stack_top(en) ((en)->stack[(en)->top].entity) +/* + * TODO: Get rid of this. + */ +#define MEDIA_ENTITY_MAX_PADS 512 + /** - * media_entity_graph_walk_start - Start walking the media graph at a given entity + * media_entity_graph_walk_init - Allocate resources for graph walk * @graph: Media graph structure that will be used to walk the graph - * @entity: Starting entity + * @mdev: Media device * - * This function initializes the graph traversal structure to walk the entities - * graph starting at the given entity. The traversal structure must not be - * modified by the caller during graph traversal. When done the structure can - * safely be freed. + * Reserve resources for graph walk in media device's current + * state. The memory must be released using + * media_entity_graph_walk_free(). + * + * Returns error on failure, zero on success. */ +__must_check int media_entity_graph_walk_init( + struct media_entity_graph *graph, struct media_device *mdev) +{ + return media_entity_enum_init(&graph->ent_enum, mdev); +} +EXPORT_SYMBOL_GPL(media_entity_graph_walk_init); + +/** + * media_entity_graph_walk_cleanup - Release resources related to graph walking + * @graph: Media graph structure that was used to walk the graph + */ +void media_entity_graph_walk_cleanup(struct media_entity_graph *graph) +{ + media_entity_enum_cleanup(&graph->ent_enum); +} +EXPORT_SYMBOL_GPL(media_entity_graph_walk_cleanup); + void media_entity_graph_walk_start(struct media_entity_graph *graph, struct media_entity *entity) { + media_entity_enum_zero(&graph->ent_enum); + media_entity_enum_set(&graph->ent_enum, entity); + graph->top = 0; graph->stack[graph->top].entity = NULL; - bitmap_zero(graph->entities, MEDIA_ENTITY_ENUM_MAX_ID); - - if (WARN_ON(entity->id >= MEDIA_ENTITY_ENUM_MAX_ID)) - return; - - __set_bit(entity->id, graph->entities); stack_push(graph, entity); } EXPORT_SYMBOL_GPL(media_entity_graph_walk_start); -/** - * media_entity_graph_walk_next - Get the next entity in the graph - * @graph: Media graph structure - * - * Perform a depth-first traversal of the given media entities graph. - * - * The graph structure must have been previously initialized with a call to - * media_entity_graph_walk_start(). - * - * Return the next entity in the graph or NULL if the whole graph have been - * traversed. - */ struct media_entity * media_entity_graph_walk_next(struct media_entity_graph *graph) { @@ -173,30 +314,30 @@ media_entity_graph_walk_next(struct media_entity_graph *graph) * top of the stack until no more entities on the level can be * found. */ - while (link_top(graph) < stack_top(graph)->num_links) { + while (link_top(graph) != &stack_top(graph)->links) { struct media_entity *entity = stack_top(graph); - struct media_link *link = &entity->links[link_top(graph)]; + struct media_link *link; struct media_entity *next; + link = list_entry(link_top(graph), typeof(*link), list); + /* The link is not enabled so we do not follow. */ if (!(link->flags & MEDIA_LNK_FL_ENABLED)) { - link_top(graph)++; + link_top(graph) = link_top(graph)->next; continue; } /* Get the entity in the other end of the link . */ next = media_entity_other(entity, link); - if (WARN_ON(next->id >= MEDIA_ENTITY_ENUM_MAX_ID)) - return NULL; /* Has the entity already been visited? */ - if (__test_and_set_bit(next->id, graph->entities)) { - link_top(graph)++; + if (media_entity_enum_test_and_set(&graph->ent_enum, next)) { + link_top(graph) = link_top(graph)->next; continue; } /* Push the new entity to stack and start over. */ - link_top(graph)++; + link_top(graph) = link_top(graph)->next; stack_push(graph, next); } @@ -208,39 +349,36 @@ EXPORT_SYMBOL_GPL(media_entity_graph_walk_next); * Pipeline management */ -/** - * media_entity_pipeline_start - Mark a pipeline as streaming - * @entity: Starting entity - * @pipe: Media pipeline to be assigned to all entities in the pipeline. - * - * Mark all entities connected to a given entity through enabled links, either - * directly or indirectly, as streaming. The given pipeline object is assigned to - * every entity in the pipeline and stored in the media_entity pipe field. - * - * Calls to this function can be nested, in which case the same number of - * media_entity_pipeline_stop() calls will be required to stop streaming. The - * pipeline pointer must be identical for all nested calls to - * media_entity_pipeline_start(). - */ __must_check int media_entity_pipeline_start(struct media_entity *entity, struct media_pipeline *pipe) { - struct media_device *mdev = entity->parent; - struct media_entity_graph graph; + struct media_device *mdev = entity->graph_obj.mdev; + struct media_entity_graph *graph = &pipe->graph; struct media_entity *entity_err = entity; + struct media_link *link; int ret; mutex_lock(&mdev->graph_mutex); - media_entity_graph_walk_start(&graph, entity); + if (!pipe->streaming_count++) { + ret = media_entity_graph_walk_init(&pipe->graph, mdev); + if (ret) + goto error_graph_walk_start; + } + + media_entity_graph_walk_start(&pipe->graph, entity); - while ((entity = media_entity_graph_walk_next(&graph))) { + while ((entity = media_entity_graph_walk_next(graph))) { DECLARE_BITMAP(active, MEDIA_ENTITY_MAX_PADS); DECLARE_BITMAP(has_no_links, MEDIA_ENTITY_MAX_PADS); - unsigned int i; entity->stream_count++; - WARN_ON(entity->pipe && entity->pipe != pipe); + + if (WARN_ON(entity->pipe && entity->pipe != pipe)) { + ret = -EBUSY; + goto error; + } + entity->pipe = pipe; /* Already streaming --- no need to check. */ @@ -253,8 +391,7 @@ __must_check int media_entity_pipeline_start(struct media_entity *entity, bitmap_zero(active, entity->num_pads); bitmap_fill(has_no_links, entity->num_pads); - for (i = 0; i < entity->num_links; i++) { - struct media_link *link = &entity->links[i]; + list_for_each_entry(link, &entity->links, list) { struct media_pad *pad = link->sink->entity == entity ? link->sink : link->source; @@ -280,7 +417,7 @@ __must_check int media_entity_pipeline_start(struct media_entity *entity, ret = entity->ops->link_validate(link); if (ret < 0 && ret != -ENOIOCTLCMD) { - dev_dbg(entity->parent->dev, + dev_dbg(entity->graph_obj.mdev->dev, "link validation failed for \"%s\":%u -> \"%s\":%u, error %d\n", link->source->entity->name, link->source->index, @@ -294,7 +431,7 @@ __must_check int media_entity_pipeline_start(struct media_entity *entity, if (!bitmap_full(active, entity->num_pads)) { ret = -EPIPE; - dev_dbg(entity->parent->dev, + dev_dbg(entity->graph_obj.mdev->dev, "\"%s\":%u must be connected by an enabled link\n", entity->name, (unsigned)find_first_zero_bit( @@ -312,9 +449,9 @@ error: * Link validation on graph failed. We revert what we did and * return the error. */ - media_entity_graph_walk_start(&graph, entity_err); + media_entity_graph_walk_start(graph, entity_err); - while ((entity_err = media_entity_graph_walk_next(&graph))) { + while ((entity_err = media_entity_graph_walk_next(graph))) { entity_err->stream_count--; if (entity_err->stream_count == 0) entity_err->pipe = NULL; @@ -327,39 +464,36 @@ error: break; } +error_graph_walk_start: + if (!--pipe->streaming_count) + media_entity_graph_walk_cleanup(graph); + mutex_unlock(&mdev->graph_mutex); return ret; } EXPORT_SYMBOL_GPL(media_entity_pipeline_start); -/** - * media_entity_pipeline_stop - Mark a pipeline as not streaming - * @entity: Starting entity - * - * Mark all entities connected to a given entity through enabled links, either - * directly or indirectly, as not streaming. The media_entity pipe field is - * reset to NULL. - * - * If multiple calls to media_entity_pipeline_start() have been made, the same - * number of calls to this function are required to mark the pipeline as not - * streaming. - */ void media_entity_pipeline_stop(struct media_entity *entity) { - struct media_device *mdev = entity->parent; - struct media_entity_graph graph; + struct media_device *mdev = entity->graph_obj.mdev; + struct media_entity_graph *graph = &entity->pipe->graph; + struct media_pipeline *pipe = entity->pipe; mutex_lock(&mdev->graph_mutex); - media_entity_graph_walk_start(&graph, entity); + WARN_ON(!pipe->streaming_count); + media_entity_graph_walk_start(graph, entity); - while ((entity = media_entity_graph_walk_next(&graph))) { + while ((entity = media_entity_graph_walk_next(graph))) { entity->stream_count--; if (entity->stream_count == 0) entity->pipe = NULL; } + if (!--pipe->streaming_count) + media_entity_graph_walk_cleanup(graph); + mutex_unlock(&mdev->graph_mutex); } EXPORT_SYMBOL_GPL(media_entity_pipeline_stop); @@ -368,44 +502,26 @@ EXPORT_SYMBOL_GPL(media_entity_pipeline_stop); * Module use count */ -/* - * media_entity_get - Get a reference to the parent module - * @entity: The entity - * - * Get a reference to the parent media device module. - * - * The function will return immediately if @entity is NULL. - * - * Return a pointer to the entity on success or NULL on failure. - */ struct media_entity *media_entity_get(struct media_entity *entity) { if (entity == NULL) return NULL; - if (entity->parent->dev && - !try_module_get(entity->parent->dev->driver->owner)) + if (entity->graph_obj.mdev->dev && + !try_module_get(entity->graph_obj.mdev->dev->driver->owner)) return NULL; return entity; } EXPORT_SYMBOL_GPL(media_entity_get); -/* - * media_entity_put - Release the reference to the parent module - * @entity: The entity - * - * Release the reference count acquired by media_entity_get(). - * - * The function will return immediately if @entity is NULL. - */ void media_entity_put(struct media_entity *entity) { if (entity == NULL) return; - if (entity->parent->dev) - module_put(entity->parent->dev->driver->owner); + if (entity->graph_obj.mdev->dev) + module_put(entity->graph_obj.mdev->dev->driver->owner); } EXPORT_SYMBOL_GPL(media_entity_put); @@ -413,29 +529,52 @@ EXPORT_SYMBOL_GPL(media_entity_put); * Links management */ -static struct media_link *media_entity_add_link(struct media_entity *entity) +static struct media_link *media_add_link(struct list_head *head) { - if (entity->num_links >= entity->max_links) { - struct media_link *links = entity->links; - unsigned int max_links = entity->max_links + 2; - unsigned int i; + struct media_link *link; + + link = kzalloc(sizeof(*link), GFP_KERNEL); + if (link == NULL) + return NULL; - links = krealloc(links, max_links * sizeof(*links), GFP_KERNEL); - if (links == NULL) - return NULL; + list_add_tail(&link->list, head); - for (i = 0; i < entity->num_links; i++) - links[i].reverse->reverse = &links[i]; + return link; +} - entity->max_links = max_links; - entity->links = links; - } +static void __media_entity_remove_link(struct media_entity *entity, + struct media_link *link) +{ + struct media_link *rlink, *tmp; + struct media_entity *remote; + + if (link->source->entity == entity) + remote = link->sink->entity; + else + remote = link->source->entity; - return &entity->links[entity->num_links++]; + list_for_each_entry_safe(rlink, tmp, &remote->links, list) { + if (rlink != link->reverse) + continue; + + if (link->source->entity == entity) + remote->num_backlinks--; + + /* Remove the remote link */ + list_del(&rlink->list); + media_gobj_destroy(&rlink->graph_obj); + kfree(rlink); + + if (--remote->num_links == 0) + break; + } + list_del(&link->list); + media_gobj_destroy(&link->graph_obj); + kfree(link); } int -media_entity_create_link(struct media_entity *source, u16 source_pad, +media_create_pad_link(struct media_entity *source, u16 source_pad, struct media_entity *sink, u16 sink_pad, u32 flags) { struct media_link *link; @@ -445,68 +584,118 @@ media_entity_create_link(struct media_entity *source, u16 source_pad, BUG_ON(source_pad >= source->num_pads); BUG_ON(sink_pad >= sink->num_pads); - link = media_entity_add_link(source); + link = media_add_link(&source->links); if (link == NULL) return -ENOMEM; link->source = &source->pads[source_pad]; link->sink = &sink->pads[sink_pad]; - link->flags = flags; + link->flags = flags & ~MEDIA_LNK_FL_INTERFACE_LINK; + + /* Initialize graph object embedded at the new link */ + media_gobj_create(source->graph_obj.mdev, MEDIA_GRAPH_LINK, + &link->graph_obj); /* Create the backlink. Backlinks are used to help graph traversal and * are not reported to userspace. */ - backlink = media_entity_add_link(sink); + backlink = media_add_link(&sink->links); if (backlink == NULL) { - source->num_links--; + __media_entity_remove_link(source, link); return -ENOMEM; } backlink->source = &source->pads[source_pad]; backlink->sink = &sink->pads[sink_pad]; backlink->flags = flags; + backlink->is_backlink = true; + + /* Initialize graph object embedded at the new link */ + media_gobj_create(sink->graph_obj.mdev, MEDIA_GRAPH_LINK, + &backlink->graph_obj); link->reverse = backlink; backlink->reverse = link; sink->num_backlinks++; + sink->num_links++; + source->num_links++; return 0; } -EXPORT_SYMBOL_GPL(media_entity_create_link); - -void __media_entity_remove_links(struct media_entity *entity) +EXPORT_SYMBOL_GPL(media_create_pad_link); + +int media_create_pad_links(const struct media_device *mdev, + const u32 source_function, + struct media_entity *source, + const u16 source_pad, + const u32 sink_function, + struct media_entity *sink, + const u16 sink_pad, + u32 flags, + const bool allow_both_undefined) { - unsigned int i; - - for (i = 0; i < entity->num_links; i++) { - struct media_link *link = &entity->links[i]; - struct media_entity *remote; - unsigned int r = 0; - - if (link->source->entity == entity) - remote = link->sink->entity; - else - remote = link->source->entity; - - while (r < remote->num_links) { - struct media_link *rlink = &remote->links[r]; + struct media_entity *entity; + unsigned function; + int ret; - if (rlink != link->reverse) { - r++; + /* Trivial case: 1:1 relation */ + if (source && sink) + return media_create_pad_link(source, source_pad, + sink, sink_pad, flags); + + /* Worse case scenario: n:n relation */ + if (!source && !sink) { + if (!allow_both_undefined) + return 0; + media_device_for_each_entity(source, mdev) { + if (source->function != source_function) continue; + media_device_for_each_entity(sink, mdev) { + if (sink->function != sink_function) + continue; + ret = media_create_pad_link(source, source_pad, + sink, sink_pad, + flags); + if (ret) + return ret; + flags &= ~(MEDIA_LNK_FL_ENABLED | + MEDIA_LNK_FL_IMMUTABLE); } + } + return 0; + } - if (link->source->entity == entity) - remote->num_backlinks--; + /* Handle 1:n and n:1 cases */ + if (source) + function = sink_function; + else + function = source_function; - if (--remote->num_links == 0) - break; + media_device_for_each_entity(entity, mdev) { + if (entity->function != function) + continue; - /* Insert last entry in place of the dropped link. */ - *rlink = remote->links[remote->num_links]; - } + if (source) + ret = media_create_pad_link(source, source_pad, + entity, sink_pad, flags); + else + ret = media_create_pad_link(entity, source_pad, + sink, sink_pad, flags); + if (ret) + return ret; + flags &= ~(MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE); } + return 0; +} +EXPORT_SYMBOL_GPL(media_create_pad_links); + +void __media_entity_remove_links(struct media_entity *entity) +{ + struct media_link *link, *tmp; + + list_for_each_entry_safe(link, tmp, &entity->links, list) + __media_entity_remove_link(entity, link); entity->num_links = 0; entity->num_backlinks = 0; @@ -515,13 +704,15 @@ EXPORT_SYMBOL_GPL(__media_entity_remove_links); void media_entity_remove_links(struct media_entity *entity) { + struct media_device *mdev = entity->graph_obj.mdev; + /* Do nothing if the entity is not registered. */ - if (entity->parent == NULL) + if (mdev == NULL) return; - mutex_lock(&entity->parent->graph_mutex); + spin_lock(&mdev->lock); __media_entity_remove_links(entity); - mutex_unlock(&entity->parent->graph_mutex); + spin_unlock(&mdev->lock); } EXPORT_SYMBOL_GPL(media_entity_remove_links); @@ -549,20 +740,6 @@ static int __media_entity_setup_link_notify(struct media_link *link, u32 flags) return 0; } -/** - * __media_entity_setup_link - Configure a media link - * @link: The link being configured - * @flags: Link configuration flags - * - * The bulk of link setup is handled by the two entities connected through the - * link. This function notifies both entities of the link configuration change. - * - * If the link is immutable or if the current and new configuration are - * identical, return immediately. - * - * The user is expected to hold link->source->parent->mutex. If not, - * media_entity_setup_link() should be used instead. - */ int __media_entity_setup_link(struct media_link *link, u32 flags) { const u32 mask = MEDIA_LNK_FL_ENABLED; @@ -590,7 +767,7 @@ int __media_entity_setup_link(struct media_link *link, u32 flags) (source->stream_count || sink->stream_count)) return -EBUSY; - mdev = source->parent; + mdev = source->graph_obj.mdev; if (mdev->link_notify) { ret = mdev->link_notify(link, flags, @@ -611,31 +788,20 @@ int media_entity_setup_link(struct media_link *link, u32 flags) { int ret; - mutex_lock(&link->source->entity->parent->graph_mutex); + mutex_lock(&link->graph_obj.mdev->graph_mutex); ret = __media_entity_setup_link(link, flags); - mutex_unlock(&link->source->entity->parent->graph_mutex); + mutex_unlock(&link->graph_obj.mdev->graph_mutex); return ret; } EXPORT_SYMBOL_GPL(media_entity_setup_link); -/** - * media_entity_find_link - Find a link between two pads - * @source: Source pad - * @sink: Sink pad - * - * Return a pointer to the link between the two entities. If no such link - * exists, return NULL. - */ struct media_link * media_entity_find_link(struct media_pad *source, struct media_pad *sink) { struct media_link *link; - unsigned int i; - - for (i = 0; i < source->entity->num_links; ++i) { - link = &source->entity->links[i]; + list_for_each_entry(link, &source->entity->links, list) { if (link->source->entity == source->entity && link->source->index == source->index && link->sink->entity == sink->entity && @@ -647,23 +813,11 @@ media_entity_find_link(struct media_pad *source, struct media_pad *sink) } EXPORT_SYMBOL_GPL(media_entity_find_link); -/** - * media_entity_remote_pad - Find the pad at the remote end of a link - * @pad: Pad at the local end of the link - * - * Search for a remote pad connected to the given pad by iterating over all - * links originating or terminating at that pad until an enabled link is found. - * - * Return a pointer to the pad at the remote end of the first found enabled - * link, or NULL if no enabled link has been found. - */ struct media_pad *media_entity_remote_pad(struct media_pad *pad) { - unsigned int i; - - for (i = 0; i < pad->entity->num_links; i++) { - struct media_link *link = &pad->entity->links[i]; + struct media_link *link; + list_for_each_entry(link, &pad->entity->links, list) { if (!(link->flags & MEDIA_LNK_FL_ENABLED)) continue; @@ -678,3 +832,113 @@ struct media_pad *media_entity_remote_pad(struct media_pad *pad) } EXPORT_SYMBOL_GPL(media_entity_remote_pad); + +static void media_interface_init(struct media_device *mdev, + struct media_interface *intf, + u32 gobj_type, + u32 intf_type, u32 flags) +{ + intf->type = intf_type; + intf->flags = flags; + INIT_LIST_HEAD(&intf->links); + + media_gobj_create(mdev, gobj_type, &intf->graph_obj); +} + +/* Functions related to the media interface via device nodes */ + +struct media_intf_devnode *media_devnode_create(struct media_device *mdev, + u32 type, u32 flags, + u32 major, u32 minor) +{ + struct media_intf_devnode *devnode; + + devnode = kzalloc(sizeof(*devnode), GFP_KERNEL); + if (!devnode) + return NULL; + + devnode->major = major; + devnode->minor = minor; + + media_interface_init(mdev, &devnode->intf, MEDIA_GRAPH_INTF_DEVNODE, + type, flags); + + return devnode; +} +EXPORT_SYMBOL_GPL(media_devnode_create); + +void media_devnode_remove(struct media_intf_devnode *devnode) +{ + media_remove_intf_links(&devnode->intf); + media_gobj_destroy(&devnode->intf.graph_obj); + kfree(devnode); +} +EXPORT_SYMBOL_GPL(media_devnode_remove); + +struct media_link *media_create_intf_link(struct media_entity *entity, + struct media_interface *intf, + u32 flags) +{ + struct media_link *link; + + link = media_add_link(&intf->links); + if (link == NULL) + return NULL; + + link->intf = intf; + link->entity = entity; + link->flags = flags | MEDIA_LNK_FL_INTERFACE_LINK; + + /* Initialize graph object embedded at the new link */ + media_gobj_create(intf->graph_obj.mdev, MEDIA_GRAPH_LINK, + &link->graph_obj); + + return link; +} +EXPORT_SYMBOL_GPL(media_create_intf_link); + +void __media_remove_intf_link(struct media_link *link) +{ + list_del(&link->list); + media_gobj_destroy(&link->graph_obj); + kfree(link); +} +EXPORT_SYMBOL_GPL(__media_remove_intf_link); + +void media_remove_intf_link(struct media_link *link) +{ + struct media_device *mdev = link->graph_obj.mdev; + + /* Do nothing if the intf is not registered. */ + if (mdev == NULL) + return; + + spin_lock(&mdev->lock); + __media_remove_intf_link(link); + spin_unlock(&mdev->lock); +} +EXPORT_SYMBOL_GPL(media_remove_intf_link); + +void __media_remove_intf_links(struct media_interface *intf) +{ + struct media_link *link, *tmp; + + list_for_each_entry_safe(link, tmp, &intf->links, list) + __media_remove_intf_link(link); + +} +EXPORT_SYMBOL_GPL(__media_remove_intf_links); + +void media_remove_intf_links(struct media_interface *intf) +{ + struct media_device *mdev = intf->graph_obj.mdev; + + /* Do nothing if the intf is not registered. */ + if (mdev == NULL) + return; + + spin_lock(&mdev->lock); + __media_remove_intf_links(intf); + spin_unlock(&mdev->lock); +} +EXPORT_SYMBOL_GPL(media_remove_intf_links); diff --git a/drivers/media/pci/bt8xx/bttv-cards.c b/drivers/media/pci/bt8xx/bttv-cards.c index 262b5cac3..baf83c36b 100644 --- a/drivers/media/pci/bt8xx/bttv-cards.c +++ b/drivers/media/pci/bt8xx/bttv-cards.c @@ -41,7 +41,7 @@ #include "bttvp.h" #include <media/v4l2-common.h> -#include <media/tvaudio.h> +#include <media/i2c/tvaudio.h> #include "bttv-audio-hook.h" /* fwd decl */ @@ -3808,7 +3808,7 @@ static void bttv_tea575x_set_direction(struct snd_tea575x *tea, bool output) gpio_inout(mask, (1 << gpio.clk) | (1 << gpio.wren)); } -static struct snd_tea575x_ops bttv_tea_ops = { +static const struct snd_tea575x_ops bttv_tea_ops = { .set_pins = bttv_tea575x_set_pins, .get_pins = bttv_tea575x_get_pins, .set_direction = bttv_tea575x_set_direction, diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 15a4ebc28..9400e9960 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -50,15 +50,15 @@ #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> #include <media/v4l2-event.h> -#include <media/tvaudio.h> -#include <media/msp3400.h> +#include <media/i2c/tvaudio.h> +#include <media/drv-intf/msp3400.h> #include <linux/dma-mapping.h> #include <asm/io.h> #include <asm/byteorder.h> -#include <media/saa6588.h> +#include <media/i2c/saa6588.h> #define BTTV_VERSION "0.9.19" diff --git a/drivers/media/pci/bt8xx/bttvp.h b/drivers/media/pci/bt8xx/bttvp.h index 31bf79d3b..b1e0023f9 100644 --- a/drivers/media/pci/bt8xx/bttvp.h +++ b/drivers/media/pci/bt8xx/bttvp.h @@ -41,8 +41,8 @@ #include <media/videobuf-dma-sg.h> #include <media/tveeprom.h> #include <media/rc-core.h> -#include <media/ir-kbd-i2c.h> -#include <media/tea575x.h> +#include <media/i2c/ir-kbd-i2c.h> +#include <media/drv-intf/tea575x.h> #include "bt848.h" #include "bttv.h" diff --git a/drivers/media/pci/bt8xx/dst_ca.c b/drivers/media/pci/bt8xx/dst_ca.c index c5cc14ef8..da8b414fd 100644 --- a/drivers/media/pci/bt8xx/dst_ca.c +++ b/drivers/media/pci/bt8xx/dst_ca.c @@ -705,7 +705,8 @@ struct dvb_device *dst_ca_attach(struct dst_state *dst, struct dvb_adapter *dvb_ struct dvb_device *dvbdev; dprintk(verbose, DST_CA_ERROR, 1, "registering DST-CA device"); - if (dvb_register_device(dvb_adapter, &dvbdev, &dvbdev_ca, dst, DVB_DEVICE_CA) == 0) { + if (dvb_register_device(dvb_adapter, &dvbdev, &dvbdev_ca, dst, + DVB_DEVICE_CA, 0) == 0) { dst->dst_ca = dvbdev; return dst->dst_ca; } diff --git a/drivers/media/pci/cobalt/cobalt-driver.c b/drivers/media/pci/cobalt/cobalt-driver.c index 8fed61ec7..8d6f04fc8 100644 --- a/drivers/media/pci/cobalt/cobalt-driver.c +++ b/drivers/media/pci/cobalt/cobalt-driver.c @@ -21,9 +21,9 @@ */ #include <linux/delay.h> -#include <media/adv7604.h> -#include <media/adv7842.h> -#include <media/adv7511.h> +#include <media/i2c/adv7604.h> +#include <media/i2c/adv7842.h> +#include <media/i2c/adv7511.h> #include <media/v4l2-event.h> #include <media/v4l2-ctrls.h> diff --git a/drivers/media/pci/cobalt/cobalt-irq.c b/drivers/media/pci/cobalt/cobalt-irq.c index 3de26d071..b190d4f81 100644 --- a/drivers/media/pci/cobalt/cobalt-irq.c +++ b/drivers/media/pci/cobalt/cobalt-irq.c @@ -18,7 +18,7 @@ * SOFTWARE. */ -#include <media/adv7604.h> +#include <media/i2c/adv7604.h> #include "cobalt-driver.h" #include "cobalt-irq.h" @@ -134,7 +134,7 @@ done: skip = true; s->skip_first_frames--; } - v4l2_get_timestamp(&cb->vb.timestamp); + cb->vb.vb2_buf.timestamp = ktime_get_ns(); /* TODO: the sequence number should be read from the FPGA so we also know about dropped frames. */ cb->vb.sequence = s->sequence++; diff --git a/drivers/media/pci/cobalt/cobalt-v4l2.c b/drivers/media/pci/cobalt/cobalt-v4l2.c index ff46e4242..c0ba458f6 100644 --- a/drivers/media/pci/cobalt/cobalt-v4l2.c +++ b/drivers/media/pci/cobalt/cobalt-v4l2.c @@ -29,8 +29,8 @@ #include <media/v4l2-ctrls.h> #include <media/v4l2-event.h> #include <media/v4l2-dv-timings.h> -#include <media/adv7604.h> -#include <media/adv7842.h> +#include <media/i2c/adv7604.h> +#include <media/i2c/adv7842.h> #include "cobalt-alsa.h" #include "cobalt-cpld.h" @@ -43,11 +43,10 @@ static const struct v4l2_dv_timings cea1080p60 = V4L2_DV_BT_CEA_1920X1080P60; /* vb2 DMA streaming ops */ -static int cobalt_queue_setup(struct vb2_queue *q, const void *parg, +static int cobalt_queue_setup(struct vb2_queue *q, unsigned int *num_buffers, unsigned int *num_planes, unsigned int sizes[], void *alloc_ctxs[]) { - const struct v4l2_format *fmt = parg; struct cobalt_stream *s = q->drv_priv; unsigned size = s->stride * s->height; @@ -55,14 +54,11 @@ static int cobalt_queue_setup(struct vb2_queue *q, const void *parg, *num_buffers = 3; if (*num_buffers > NR_BUFS) *num_buffers = NR_BUFS; + alloc_ctxs[0] = s->cobalt->alloc_ctx; + if (*num_planes) + return sizes[0] < size ? -EINVAL : 0; *num_planes = 1; - if (fmt) { - if (fmt->fmt.pix.sizeimage < size) - return -EINVAL; - size = fmt->fmt.pix.sizeimage; - } sizes[0] = size; - alloc_ctxs[0] = s->cobalt->alloc_ctx; return 0; } @@ -649,7 +645,7 @@ static int cobalt_s_dv_timings(struct file *file, void *priv_fh, return 0; } - if (v4l2_match_dv_timings(timings, &s->timings, 0)) + if (v4l2_match_dv_timings(timings, &s->timings, 0, false)) return 0; if (vb2_is_busy(&s->q)) diff --git a/drivers/media/pci/cx18/cx18-cards.c b/drivers/media/pci/cx18/cx18-cards.c index c07c849b1..5e01ea441 100644 --- a/drivers/media/pci/cx18/cx18-cards.c +++ b/drivers/media/pci/cx18/cx18-cards.c @@ -26,7 +26,7 @@ #include "cx18-cards.h" #include "cx18-av-core.h" #include "cx18-i2c.h" -#include <media/cs5345.h> +#include <media/i2c/cs5345.h> #define V4L2_STD_PAL_SECAM (V4L2_STD_PAL|V4L2_STD_SECAM) diff --git a/drivers/media/pci/cx18/cx18-controls.c b/drivers/media/pci/cx18/cx18-controls.c index 71227a155..adb5a8c72 100644 --- a/drivers/media/pci/cx18/cx18-controls.c +++ b/drivers/media/pci/cx18/cx18-controls.c @@ -126,7 +126,7 @@ static int cx18_s_audio_mode(struct cx2341x_handler *cxhdl, u32 val) return 0; } -struct cx2341x_handler_ops cx18_cxhdl_ops = { +const struct cx2341x_handler_ops cx18_cxhdl_ops = { .s_audio_mode = cx18_s_audio_mode, .s_audio_sampling_freq = cx18_s_audio_sampling_freq, .s_video_encoding = cx18_s_video_encoding, diff --git a/drivers/media/pci/cx18/cx18-controls.h b/drivers/media/pci/cx18/cx18-controls.h index cb5dfc7b2..326794887 100644 --- a/drivers/media/pci/cx18/cx18-controls.h +++ b/drivers/media/pci/cx18/cx18-controls.h @@ -21,4 +21,4 @@ * 02111-1307 USA */ -extern struct cx2341x_handler_ops cx18_cxhdl_ops; +extern const struct cx2341x_handler_ops cx18_cxhdl_ops; diff --git a/drivers/media/pci/cx18/cx18-driver.h b/drivers/media/pci/cx18/cx18-driver.h index b15beed2d..7e31f2a2e 100644 --- a/drivers/media/pci/cx18/cx18-driver.h +++ b/drivers/media/pci/cx18/cx18-driver.h @@ -49,7 +49,7 @@ #include <media/v4l2-device.h> #include <media/v4l2-fh.h> #include <media/tuner.h> -#include <media/ir-kbd-i2c.h> +#include <media/i2c/ir-kbd-i2c.h> #include "cx18-mailbox.h" #include "cx18-av-core.h" #include "cx23418.h" diff --git a/drivers/media/pci/cx18/cx18-ioctl.c b/drivers/media/pci/cx18/cx18-ioctl.c index 55525af1f..eeb741c7d 100644 --- a/drivers/media/pci/cx18/cx18-ioctl.c +++ b/drivers/media/pci/cx18/cx18-ioctl.c @@ -453,8 +453,8 @@ static int cx18_cropcap(struct file *file, void *fh, if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - cropcap->pixelaspect.numerator = cx->is_50hz ? 59 : 10; - cropcap->pixelaspect.denominator = cx->is_50hz ? 54 : 11; + cropcap->pixelaspect.numerator = cx->is_50hz ? 54 : 11; + cropcap->pixelaspect.denominator = cx->is_50hz ? 59 : 10; return 0; } diff --git a/drivers/media/pci/cx18/cx23418.h b/drivers/media/pci/cx18/cx23418.h index 767a8d23e..67ffe65b5 100644 --- a/drivers/media/pci/cx18/cx23418.h +++ b/drivers/media/pci/cx18/cx23418.h @@ -22,7 +22,7 @@ #ifndef CX23418_H #define CX23418_H -#include <media/cx2341x.h> +#include <media/drv-intf/cx2341x.h> #define MGR_CMD_MASK 0x40000000 /* The MSB of the command code indicates that this is the completion of a diff --git a/drivers/media/pci/cx23885/Kconfig b/drivers/media/pci/cx23885/Kconfig index 2e1b88ccd..3435bbaa3 100644 --- a/drivers/media/pci/cx23885/Kconfig +++ b/drivers/media/pci/cx23885/Kconfig @@ -10,6 +10,7 @@ config VIDEO_CX23885 select VIDEOBUF2_DMA_SG select VIDEO_CX25840 select VIDEO_CX2341X + select VIDEO_CS3308 select DVB_DIB7000P if MEDIA_SUBDRV_AUTOSELECT select DVB_DRXK if MEDIA_SUBDRV_AUTOSELECT select DVB_S5H1409 if MEDIA_SUBDRV_AUTOSELECT diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c index b1eaaeeb9..1eede74fe 100644 --- a/drivers/media/pci/cx23885/cx23885-417.c +++ b/drivers/media/pci/cx23885/cx23885-417.c @@ -30,7 +30,7 @@ #include <linux/slab.h> #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> -#include <media/cx2341x.h> +#include <media/drv-intf/cx2341x.h> #include "cx23885.h" #include "cx23885-ioctl.h" @@ -1138,7 +1138,7 @@ static int cx23885_initialize_codec(struct cx23885_dev *dev, int startencoder) /* ------------------------------------------------------------------ */ -static int queue_setup(struct vb2_queue *q, const void *parg, +static int queue_setup(struct vb2_queue *q, unsigned int *num_buffers, unsigned int *num_planes, unsigned int sizes[], void *alloc_ctxs[]) { diff --git a/drivers/media/pci/cx23885/cx23885-cards.c b/drivers/media/pci/cx23885/cx23885-cards.c index 087eb67f9..ff0789328 100644 --- a/drivers/media/pci/cx23885/cx23885-cards.c +++ b/drivers/media/pci/cx23885/cx23885-cards.c @@ -19,7 +19,7 @@ #include <linux/module.h> #include <linux/pci.h> #include <linux/delay.h> -#include <media/cx25840.h> +#include <media/drv-intf/cx25840.h> #include <linux/firmware.h> #include <misc/altera.h> @@ -715,6 +715,56 @@ struct cx23885_board cx23885_boards[] = { .portb = CX23885_MPEG_DVB, .portc = CX23885_MPEG_DVB, }, + [CX23885_BOARD_VIEWCAST_260E] = { + .name = "ViewCast 260e", + .porta = CX23885_ANALOG_VIDEO, + .force_bff = 1, + .input = {{ + .type = CX23885_VMUX_COMPOSITE1, + .vmux = CX25840_VIN6_CH1, + .amux = CX25840_AUDIO7, + }, { + .type = CX23885_VMUX_SVIDEO, + .vmux = CX25840_VIN7_CH3 | + CX25840_VIN5_CH1 | + CX25840_SVIDEO_ON, + .amux = CX25840_AUDIO7, + }, { + .type = CX23885_VMUX_COMPONENT, + .vmux = CX25840_VIN7_CH3 | + CX25840_VIN6_CH2 | + CX25840_VIN5_CH1 | + CX25840_COMPONENT_ON, + .amux = CX25840_AUDIO7, + } }, + }, + [CX23885_BOARD_VIEWCAST_460E] = { + .name = "ViewCast 460e", + .porta = CX23885_ANALOG_VIDEO, + .force_bff = 1, + .input = {{ + .type = CX23885_VMUX_COMPOSITE1, + .vmux = CX25840_VIN4_CH1, + .amux = CX25840_AUDIO7, + }, { + .type = CX23885_VMUX_SVIDEO, + .vmux = CX25840_VIN7_CH3 | + CX25840_VIN6_CH1 | + CX25840_SVIDEO_ON, + .amux = CX25840_AUDIO7, + }, { + .type = CX23885_VMUX_COMPONENT, + .vmux = CX25840_VIN7_CH3 | + CX25840_VIN6_CH1 | + CX25840_VIN5_CH2 | + CX25840_COMPONENT_ON, + .amux = CX25840_AUDIO7, + }, { + .type = CX23885_VMUX_COMPOSITE2, + .vmux = CX25840_VIN6_CH1, + .amux = CX25840_AUDIO7, + } }, + }, }; const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); @@ -1002,6 +1052,14 @@ struct cx23885_subid cx23885_subids[] = { .subvendor = 0x0070, .subdevice = 0xf038, .card = CX23885_BOARD_HAUPPAUGE_HVR5525, + }, { + .subvendor = 0x1576, + .subdevice = 0x0260, + .card = CX23885_BOARD_VIEWCAST_260E, + }, { + .subvendor = 0x1576, + .subdevice = 0x0460, + .card = CX23885_BOARD_VIEWCAST_460E, }, }; const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); @@ -1034,6 +1092,28 @@ void cx23885_card_list(struct cx23885_dev *dev) dev->name, i, cx23885_boards[i].name); } +static void viewcast_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) +{ + u32 sn; + + /* The serial number record begins with tag 0x59 */ + if (*(eeprom_data + 0x00) != 0x59) { + pr_info("%s() eeprom records are undefined, no serial number\n", + __func__); + return; + } + + sn = (*(eeprom_data + 0x06) << 24) | + (*(eeprom_data + 0x05) << 16) | + (*(eeprom_data + 0x04) << 8) | + (*(eeprom_data + 0x03)); + + pr_info("%s: card '%s' sn# MM%d\n", + dev->name, + cx23885_boards[dev->board].name, + sn); +} + static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) { struct tveeprom tv; @@ -1671,6 +1751,12 @@ void cx23885_gpio_setup(struct cx23885_dev *dev) cx23885_gpio_set(dev, GPIO_8 | GPIO_9); msleep(100); break; + case CX23885_BOARD_VIEWCAST_260E: + case CX23885_BOARD_VIEWCAST_460E: + /* For documentation purposes, it's worth noting that this + * card does not have any GPIO's connected to subcomponents. + */ + break; } } @@ -1917,6 +2003,14 @@ void cx23885_card_setup(struct cx23885_dev *dev) if (dev->i2c_bus[0].i2c_rc == 0) hauppauge_eeprom(dev, eeprom+0xc0); break; + case CX23885_BOARD_VIEWCAST_260E: + case CX23885_BOARD_VIEWCAST_460E: + dev->i2c_bus[1].i2c_client.addr = 0xa0 >> 1; + tveeprom_read(&dev->i2c_bus[1].i2c_client, + eeprom, sizeof(eeprom)); + if (dev->i2c_bus[0].i2c_rc == 0) + viewcast_eeprom(dev, eeprom); + break; } switch (dev->board) { @@ -2120,6 +2214,8 @@ void cx23885_card_setup(struct cx23885_dev *dev) case CX23885_BOARD_DVBSKY_S950: case CX23885_BOARD_DVBSKY_S952: case CX23885_BOARD_DVBSKY_T982: + case CX23885_BOARD_VIEWCAST_260E: + case CX23885_BOARD_VIEWCAST_460E: dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_bus[2].i2c_adap, "cx25840", 0x88 >> 1, NULL); @@ -2130,6 +2226,24 @@ void cx23885_card_setup(struct cx23885_dev *dev) break; } + switch (dev->board) { + case CX23885_BOARD_VIEWCAST_260E: + v4l2_i2c_new_subdev(&dev->v4l2_dev, + &dev->i2c_bus[0].i2c_adap, + "cs3308", 0x82 >> 1, NULL); + break; + case CX23885_BOARD_VIEWCAST_460E: + /* This cs3308 controls the audio from the breakout cable */ + v4l2_i2c_new_subdev(&dev->v4l2_dev, + &dev->i2c_bus[0].i2c_adap, + "cs3308", 0x80 >> 1, NULL); + /* This cs3308 controls the audio from the onboard header */ + v4l2_i2c_new_subdev(&dev->v4l2_dev, + &dev->i2c_bus[0].i2c_adap, + "cs3308", 0x82 >> 1, NULL); + break; + } + /* AUX-PLL 27MHz CLK */ switch (dev->board) { case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c index e8f847226..813c217b5 100644 --- a/drivers/media/pci/cx23885/cx23885-core.c +++ b/drivers/media/pci/cx23885/cx23885-core.c @@ -427,7 +427,7 @@ static void cx23885_wakeup(struct cx23885_tsport *port, buf = list_entry(q->active.next, struct cx23885_buffer, queue); - v4l2_get_timestamp(&buf->vb.timestamp); + buf->vb.vb2_buf.timestamp = ktime_get_ns(); buf->vb.sequence = q->count++; dprintk(1, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.vb2_buf.index, @@ -968,6 +968,16 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) call_all(dev, core, s_power, 0); cx23885_ir_init(dev); + if (dev->board == CX23885_BOARD_VIEWCAST_460E) { + /* + * GPIOs 9/8 are input detection bits for the breakout video + * (gpio 8) and audio (gpio 9) cables. When they're attached, + * this gpios are pulled high. Make sure these GPIOs are marked + * as inputs. + */ + cx23885_gpio_enable(dev, 0x300, 0); + } + if (cx23885_boards[dev->board].porta == CX23885_ANALOG_VIDEO) { if (cx23885_video_register(dev) < 0) { printk(KERN_ERR "%s() Failed to register analog " diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c index 012382f86..b46c0d231 100644 --- a/drivers/media/pci/cx23885/cx23885-dvb.c +++ b/drivers/media/pci/cx23885/cx23885-dvb.c @@ -92,7 +92,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); /* ------------------------------------------------------------------ */ -static int queue_setup(struct vb2_queue *q, const void *parg, +static int queue_setup(struct vb2_queue *q, unsigned int *num_buffers, unsigned int *num_planes, unsigned int sizes[], void *alloc_ctxs[]) { @@ -2168,11 +2168,12 @@ static int dvb_register(struct cx23885_tsport *port) } port->i2c_client_tuner = client_tuner; break; - case CX23885_BOARD_HAUPPAUGE_HVR5525: - switch (port->nr) { + case CX23885_BOARD_HAUPPAUGE_HVR5525: { struct m88rs6000t_config m88rs6000t_config; struct a8293_platform_data a8293_pdata = {}; + switch (port->nr) { + /* port b - satellite */ case 1: /* attach frontend */ @@ -2267,6 +2268,7 @@ static int dvb_register(struct cx23885_tsport *port) break; } break; + } default: printk(KERN_INFO "%s: The frontend of your DVB/ATSC card " " isn't supported yet\n", diff --git a/drivers/media/pci/cx23885/cx23885-i2c.c b/drivers/media/pci/cx23885/cx23885-i2c.c index 1135ea3f6..ae061b358 100644 --- a/drivers/media/pci/cx23885/cx23885-i2c.c +++ b/drivers/media/pci/cx23885/cx23885-i2c.c @@ -279,6 +279,8 @@ static char *i2c_devs[128] = { [0x10 >> 1] = "tda10048", [0x12 >> 1] = "dib7000pc", [0x1c >> 1] = "lgdt3303", + [0x80 >> 1] = "cs3308", + [0x82 >> 1] = "cs3308", [0x86 >> 1] = "tda9887", [0x32 >> 1] = "cx24227", [0x88 >> 1] = "cx25837", diff --git a/drivers/media/pci/cx23885/cx23885-input.c b/drivers/media/pci/cx23885/cx23885-input.c index 088799c3b..64328d08a 100644 --- a/drivers/media/pci/cx23885/cx23885-input.c +++ b/drivers/media/pci/cx23885/cx23885-input.c @@ -268,7 +268,7 @@ int cx23885_input_init(struct cx23885_dev *dev) struct rc_dev *rc; char *rc_map; enum rc_driver_type driver_type; - unsigned long allowed_protos; + u64 allowed_protos; int ret; diff --git a/drivers/media/pci/cx23885/cx23885-vbi.c b/drivers/media/pci/cx23885/cx23885-vbi.c index cf3cb1324..39750ebcc 100644 --- a/drivers/media/pci/cx23885/cx23885-vbi.c +++ b/drivers/media/pci/cx23885/cx23885-vbi.c @@ -83,7 +83,7 @@ int cx23885_vbi_irq(struct cx23885_dev *dev, u32 status) if (status & VID_BC_MSK_VBI_RISCI1) { dprintk(1, "%s() VID_BC_MSK_VBI_RISCI1\n", __func__); spin_lock(&dev->slock); - count = cx_read(VID_A_GPCNT); + count = cx_read(VBI_A_GPCNT); cx23885_video_wakeup(dev, &dev->vbiq, count); spin_unlock(&dev->slock); handled++; @@ -103,7 +103,6 @@ static int cx23885_start_vbi_dma(struct cx23885_dev *dev, VBI_LINE_LENGTH, buf->risc.dma); /* reset counter */ - cx_write(VID_A_GPCNT_CTL, 3); cx_write(VID_A_VBI_CTRL, 3); cx_write(VBI_A_GPCNT_CTL, 3); q->count = 0; @@ -121,7 +120,7 @@ static int cx23885_start_vbi_dma(struct cx23885_dev *dev, /* ------------------------------------------------------------------ */ -static int queue_setup(struct vb2_queue *q, const void *parg, +static int queue_setup(struct vb2_queue *q, unsigned int *num_buffers, unsigned int *num_planes, unsigned int sizes[], void *alloc_ctxs[]) { diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index 2d2709d3b..53df50465 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -35,7 +35,7 @@ #include "cx23885-ioctl.h" #include "tuner-xc2028.h" -#include <media/cx25840.h> +#include <media/drv-intf/cx25840.h> MODULE_DESCRIPTION("v4l2 driver module for cx23885 based TV cards"); MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>"); @@ -105,7 +105,7 @@ void cx23885_video_wakeup(struct cx23885_dev *dev, struct cx23885_buffer, queue); buf->vb.sequence = q->count++; - v4l2_get_timestamp(&buf->vb.timestamp); + buf->vb.vb2_buf.timestamp = ktime_get_ns(); dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.vb2_buf.index, count, q->count); list_del(&buf->queue); @@ -114,11 +114,19 @@ void cx23885_video_wakeup(struct cx23885_dev *dev, int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm) { + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + .format.code = MEDIA_BUS_FMT_FIXED, + }; + dprintk(1, "%s(norm = 0x%08x) name: [%s]\n", __func__, (unsigned int)norm, v4l2_norm_to_name(norm)); + if (dev->tvnorm == norm) + return 0; + if (dev->tvnorm != norm) { if (vb2_is_busy(&dev->vb2_vidq) || vb2_is_busy(&dev->vb2_vbiq) || vb2_is_busy(&dev->vb2_mpegq)) @@ -126,9 +134,17 @@ int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm) } dev->tvnorm = norm; + dev->width = 720; + dev->height = norm_maxh(norm); + dev->field = V4L2_FIELD_INTERLACED; call_all(dev, video, s_std, norm); + format.format.width = dev->width; + format.format.height = dev->height; + format.format.field = dev->field; + call_all(dev, pad, set_fmt, NULL, &format); + return 0; } @@ -247,7 +263,9 @@ static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input) (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255_22111) || (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1850) || (dev->board == CX23885_BOARD_MYGICA_X8507) || - (dev->board == CX23885_BOARD_AVERMEDIA_HC81R)) { + (dev->board == CX23885_BOARD_AVERMEDIA_HC81R) || + (dev->board == CX23885_BOARD_VIEWCAST_260E) || + (dev->board == CX23885_BOARD_VIEWCAST_460E)) { /* Configure audio routing */ v4l2_subdev_call(dev->sd_cx25840, audio, s_routing, INPUT(input)->amux, 0, 0); @@ -315,7 +333,7 @@ static int cx23885_start_video_dma(struct cx23885_dev *dev, return 0; } -static int queue_setup(struct vb2_queue *q, const void *parg, +static int queue_setup(struct vb2_queue *q, unsigned int *num_buffers, unsigned int *num_planes, unsigned int sizes[], void *alloc_ctxs[]) { @@ -545,7 +563,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, return -EINVAL; field = f->fmt.pix.field; - maxw = norm_maxw(dev->tvnorm); + maxw = 720; maxh = norm_maxh(dev->tvnorm); if (V4L2_FIELD_ANY == field) { @@ -648,6 +666,26 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, return 0; } +static int vidioc_cropcap(struct file *file, void *priv, + struct v4l2_cropcap *cc) +{ + struct cx23885_dev *dev = video_drvdata(file); + bool is_50hz = dev->tvnorm & V4L2_STD_625_50; + + if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + cc->bounds.left = 0; + cc->bounds.top = 0; + cc->bounds.width = 720; + cc->bounds.height = norm_maxh(dev->tvnorm); + cc->defrect = cc->bounds; + cc->pixelaspect.numerator = is_50hz ? 54 : 11; + cc->pixelaspect.denominator = is_50hz ? 59 : 10; + + return 0; +} + static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) { struct cx23885_dev *dev = video_drvdata(file); @@ -1082,6 +1120,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_dqbuf = vb2_ioctl_dqbuf, .vidioc_streamon = vb2_ioctl_streamon, .vidioc_streamoff = vb2_ioctl_streamoff, + .vidioc_cropcap = vidioc_cropcap, .vidioc_s_std = vidioc_s_std, .vidioc_g_std = vidioc_g_std, .vidioc_enum_input = vidioc_enum_input, diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index c5ba0833f..b1a540940 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h @@ -30,7 +30,7 @@ #include <media/rc-core.h> #include "cx23885-reg.h" -#include "media/cx2341x.h" +#include "media/drv-intf/cx2341x.h" #include <linux/mutex.h> @@ -101,6 +101,8 @@ #define CX23885_BOARD_DVBSKY_T982 51 #define CX23885_BOARD_HAUPPAUGE_HVR5525 52 #define CX23885_BOARD_HAUPPAUGE_STARBURST 53 +#define CX23885_BOARD_VIEWCAST_260E 54 +#define CX23885_BOARD_VIEWCAST_460E 55 #define GPIO_0 0x00000001 #define GPIO_1 0x00000002 @@ -627,11 +629,6 @@ extern int cx23885_risc_databuffer(struct pci_dev *pci, /* ----------------------------------------------------------- */ /* tv norms */ -static inline unsigned int norm_maxw(v4l2_std_id norm) -{ - return (norm & V4L2_STD_525_60) ? 720 : 768; -} - static inline unsigned int norm_maxh(v4l2_std_id norm) { return (norm & V4L2_STD_525_60) ? 480 : 576; diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index 26e3e296d..c48bba9da 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -130,7 +130,7 @@ int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status) buf = list_entry(dmaq->active.next, struct cx25821_buffer, queue); - v4l2_get_timestamp(&buf->vb.timestamp); + buf->vb.vb2_buf.timestamp = ktime_get_ns(); buf->vb.sequence = dmaq->count++; list_del(&buf->queue); vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE); @@ -141,20 +141,20 @@ int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status) return handled; } -static int cx25821_queue_setup(struct vb2_queue *q, const void *parg, +static int cx25821_queue_setup(struct vb2_queue *q, unsigned int *num_buffers, unsigned int *num_planes, unsigned int sizes[], void *alloc_ctxs[]) { - const struct v4l2_format *fmt = parg; struct cx25821_channel *chan = q->drv_priv; unsigned size = (chan->fmt->depth * chan->width * chan->height) >> 3; - if (fmt && fmt->fmt.pix.sizeimage < size) - return -EINVAL; + alloc_ctxs[0] = chan->dev->alloc_ctx; + + if (*num_planes) + return sizes[0] < size ? -EINVAL : 0; *num_planes = 1; - sizes[0] = fmt ? fmt->fmt.pix.sizeimage : size; - alloc_ctxs[0] = chan->dev->alloc_ctx; + sizes[0] = size; return 0; } diff --git a/drivers/media/pci/cx88/cx88-alsa.c b/drivers/media/pci/cx88/cx88-alsa.c index 1b5268f9b..e158a1da1 100644 --- a/drivers/media/pci/cx88/cx88-alsa.c +++ b/drivers/media/pci/cx88/cx88-alsa.c @@ -40,7 +40,7 @@ #include <sound/control.h> #include <sound/initval.h> #include <sound/tlv.h> -#include <media/wm8775.h> +#include <media/i2c/wm8775.h> #include "cx88.h" #include "cx88-reg.h" diff --git a/drivers/media/pci/cx88/cx88-blackbird.c b/drivers/media/pci/cx88/cx88-blackbird.c index 0978e7113..34e4e754b 100644 --- a/drivers/media/pci/cx88/cx88-blackbird.c +++ b/drivers/media/pci/cx88/cx88-blackbird.c @@ -36,7 +36,7 @@ #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> #include <media/v4l2-event.h> -#include <media/cx2341x.h> +#include <media/drv-intf/cx2341x.h> #include "cx88.h" @@ -637,7 +637,7 @@ static int blackbird_stop_codec(struct cx8802_dev *dev) /* ------------------------------------------------------------------ */ -static int queue_setup(struct vb2_queue *q, const void *parg, +static int queue_setup(struct vb2_queue *q, unsigned int *num_buffers, unsigned int *num_planes, unsigned int sizes[], void *alloc_ctxs[]) { diff --git a/drivers/media/pci/cx88/cx88-core.c b/drivers/media/pci/cx88/cx88-core.c index 9a43c7826..46fe8c1eb 100644 --- a/drivers/media/pci/cx88/cx88-core.c +++ b/drivers/media/pci/cx88/cx88-core.c @@ -518,7 +518,7 @@ void cx88_wakeup(struct cx88_core *core, buf = list_entry(q->active.next, struct cx88_buffer, list); - v4l2_get_timestamp(&buf->vb.timestamp); + buf->vb.vb2_buf.timestamp = ktime_get_ns(); buf->vb.field = core->field; buf->vb.sequence = q->count++; list_del(&buf->list); diff --git a/drivers/media/pci/cx88/cx88-dvb.c b/drivers/media/pci/cx88/cx88-dvb.c index 7d9dfe55b..8c9b1f1ab 100644 --- a/drivers/media/pci/cx88/cx88-dvb.c +++ b/drivers/media/pci/cx88/cx88-dvb.c @@ -82,7 +82,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); /* ------------------------------------------------------------------ */ -static int queue_setup(struct vb2_queue *q, const void *parg, +static int queue_setup(struct vb2_queue *q, unsigned int *num_buffers, unsigned int *num_planes, unsigned int sizes[], void *alloc_ctxs[]) { diff --git a/drivers/media/pci/cx88/cx88-vbi.c b/drivers/media/pci/cx88/cx88-vbi.c index 007a5eee8..ccc646d81 100644 --- a/drivers/media/pci/cx88/cx88-vbi.c +++ b/drivers/media/pci/cx88/cx88-vbi.c @@ -107,7 +107,7 @@ int cx8800_restart_vbi_queue(struct cx8800_dev *dev, /* ------------------------------------------------------------------ */ -static int queue_setup(struct vb2_queue *q, const void *parg, +static int queue_setup(struct vb2_queue *q, unsigned int *num_buffers, unsigned int *num_planes, unsigned int sizes[], void *alloc_ctxs[]) { diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c index aef9acf35..5f331df65 100644 --- a/drivers/media/pci/cx88/cx88-video.c +++ b/drivers/media/pci/cx88/cx88-video.c @@ -41,7 +41,7 @@ #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> #include <media/v4l2-event.h> -#include <media/wm8775.h> +#include <media/i2c/wm8775.h> MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards"); MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); @@ -429,7 +429,7 @@ static int restart_video_queue(struct cx8800_dev *dev, /* ------------------------------------------------------------------ */ -static int queue_setup(struct vb2_queue *q, const void *parg, +static int queue_setup(struct vb2_queue *q, unsigned int *num_buffers, unsigned int *num_planes, unsigned int sizes[], void *alloc_ctxs[]) { diff --git a/drivers/media/pci/cx88/cx88.h b/drivers/media/pci/cx88/cx88.h index 2996eb3ea..78f817ee7 100644 --- a/drivers/media/pci/cx88/cx88.h +++ b/drivers/media/pci/cx88/cx88.h @@ -30,10 +30,10 @@ #include <media/tuner.h> #include <media/tveeprom.h> #include <media/videobuf2-dma-sg.h> -#include <media/cx2341x.h> +#include <media/drv-intf/cx2341x.h> #include <media/videobuf2-dvb.h> -#include <media/ir-kbd-i2c.h> -#include <media/wm8775.h> +#include <media/i2c/ir-kbd-i2c.h> +#include <media/i2c/wm8775.h> #include "cx88-reg.h" #include "tuner-xc2028.h" diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c b/drivers/media/pci/ddbridge/ddbridge-core.c index 0ac2dd35f..9d5b31414 100644 --- a/drivers/media/pci/ddbridge/ddbridge-core.c +++ b/drivers/media/pci/ddbridge/ddbridge-core.c @@ -81,13 +81,13 @@ static int i2c_read_reg16(struct i2c_adapter *adapter, u8 adr, static int ddb_i2c_cmd(struct ddb_i2c *i2c, u32 adr, u32 cmd) { struct ddb *dev = i2c->dev; - int stat; + long stat; u32 val; i2c->done = 0; ddbwritel((adr << 9) | cmd, i2c->regs + I2C_COMMAND); stat = wait_event_timeout(i2c->wq, i2c->done == 1, HZ); - if (stat <= 0) { + if (stat == 0) { printk(KERN_ERR "I2C timeout\n"); { /* MSI debugging*/ u32 istat = ddbreadl(INTERRUPT_STATUS); @@ -1065,7 +1065,7 @@ static int ddb_ci_attach(struct ddb_port *port) port->en, 0, 1); ret = dvb_register_device(&port->output->adap, &port->output->dev, &dvbdev_ci, (void *) port->output, - DVB_DEVICE_SEC); + DVB_DEVICE_SEC, 0); return ret; } diff --git a/drivers/media/pci/dm1105/dm1105.c b/drivers/media/pci/dm1105/dm1105.c index 88915fb87..5dd504741 100644 --- a/drivers/media/pci/dm1105/dm1105.c +++ b/drivers/media/pci/dm1105/dm1105.c @@ -1206,7 +1206,6 @@ static void dm1105_remove(struct pci_dev *pdev) i2c_del_adapter(&dev->i2c_adap); dm1105_hw_exit(dev); - synchronize_irq(pdev->irq); free_irq(pdev->irq, dev); pci_iounmap(pdev, dev->io_mem); pci_release_regions(pdev); diff --git a/drivers/media/pci/dt3155/dt3155.c b/drivers/media/pci/dt3155/dt3155.c index d84abde5e..568c0c8fb 100644 --- a/drivers/media/pci/dt3155/dt3155.c +++ b/drivers/media/pci/dt3155/dt3155.c @@ -131,22 +131,21 @@ static int wait_i2c_reg(void __iomem *addr) } static int -dt3155_queue_setup(struct vb2_queue *vq, const void *parg, +dt3155_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *num_planes, unsigned int sizes[], void *alloc_ctxs[]) { - const struct v4l2_format *fmt = parg; struct dt3155_priv *pd = vb2_get_drv_priv(vq); unsigned size = pd->width * pd->height; if (vq->num_buffers + *nbuffers < 2) *nbuffers = 2 - vq->num_buffers; - if (fmt && fmt->fmt.pix.sizeimage < size) - return -EINVAL; - *num_planes = 1; - sizes[0] = fmt ? fmt->fmt.pix.sizeimage : size; alloc_ctxs[0] = pd->alloc_ctx; + if (*num_planes) + return sizes[0] < size ? -EINVAL : 0; + *num_planes = 1; + sizes[0] = size; return 0; } @@ -271,7 +270,7 @@ static irqreturn_t dt3155_irq_handler_even(int irq, void *dev_id) spin_lock(&ipd->lock); if (ipd->curr_buf && !list_empty(&ipd->dmaq)) { - v4l2_get_timestamp(&ipd->curr_buf->timestamp); + ipd->curr_buf->vb2_buf.timestamp = ktime_get_ns(); ipd->curr_buf->sequence = ipd->sequence++; ipd->curr_buf->field = V4L2_FIELD_NONE; vb2_buffer_done(&ipd->curr_buf->vb2_buf, VB2_BUF_STATE_DONE); diff --git a/drivers/media/pci/ivtv/ivtv-cards.c b/drivers/media/pci/ivtv/ivtv-cards.c index 145e4749a..410d97bdf 100644 --- a/drivers/media/pci/ivtv/ivtv-cards.c +++ b/drivers/media/pci/ivtv/ivtv-cards.c @@ -22,12 +22,12 @@ #include "ivtv-cards.h" #include "ivtv-i2c.h" -#include <media/msp3400.h> -#include <media/m52790.h> -#include <media/wm8775.h> -#include <media/cs53l32a.h> -#include <media/cx25840.h> -#include <media/upd64031a.h> +#include <media/drv-intf/msp3400.h> +#include <media/i2c/m52790.h> +#include <media/i2c/wm8775.h> +#include <media/i2c/cs53l32a.h> +#include <media/drv-intf/cx25840.h> +#include <media/i2c/upd64031a.h> #define MSP_TUNER MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1, \ MSP_DSP_IN_TUNER, MSP_DSP_IN_TUNER) diff --git a/drivers/media/pci/ivtv/ivtv-controls.c b/drivers/media/pci/ivtv/ivtv-controls.c index 8a55ccb8f..9666ca015 100644 --- a/drivers/media/pci/ivtv/ivtv-controls.c +++ b/drivers/media/pci/ivtv/ivtv-controls.c @@ -96,7 +96,7 @@ static int ivtv_s_audio_mode(struct cx2341x_handler *cxhdl, u32 val) return 0; } -struct cx2341x_handler_ops ivtv_cxhdl_ops = { +const struct cx2341x_handler_ops ivtv_cxhdl_ops = { .s_audio_mode = ivtv_s_audio_mode, .s_audio_sampling_freq = ivtv_s_audio_sampling_freq, .s_video_encoding = ivtv_s_video_encoding, diff --git a/drivers/media/pci/ivtv/ivtv-controls.h b/drivers/media/pci/ivtv/ivtv-controls.h index 3999e6358..ea397ba83 100644 --- a/drivers/media/pci/ivtv/ivtv-controls.h +++ b/drivers/media/pci/ivtv/ivtv-controls.h @@ -21,7 +21,7 @@ #ifndef IVTV_CONTROLS_H #define IVTV_CONTROLS_H -extern struct cx2341x_handler_ops ivtv_cxhdl_ops; +extern const struct cx2341x_handler_ops ivtv_cxhdl_ops; extern const struct v4l2_ctrl_ops ivtv_hdl_out_ops; int ivtv_g_pts_frame(struct ivtv *itv, s64 *pts, s64 *frame); diff --git a/drivers/media/pci/ivtv/ivtv-driver.c b/drivers/media/pci/ivtv/ivtv-driver.c index cb567aa60..313aa6c2c 100644 --- a/drivers/media/pci/ivtv/ivtv-driver.c +++ b/drivers/media/pci/ivtv/ivtv-driver.c @@ -57,7 +57,7 @@ #include "ivtv-gpio.h" #include <linux/dma-mapping.h> #include <media/tveeprom.h> -#include <media/saa7115.h> +#include <media/i2c/saa7115.h> #include "tuner-xc2028.h" /* If you have already X v4l cards, then set this to X. This way @@ -826,7 +826,7 @@ static void ivtv_init_struct2(struct ivtv *itv) IVTV_CARD_INPUT_VID_TUNER) break; } - if (i == itv->nof_inputs) + if (i >= itv->nof_inputs) i = 0; itv->active_input = i; itv->audio_input = itv->card->video_inputs[i].audio_index; diff --git a/drivers/media/pci/ivtv/ivtv-driver.h b/drivers/media/pci/ivtv/ivtv-driver.h index ee0ef6e48..6c08dae67 100644 --- a/drivers/media/pci/ivtv/ivtv-driver.h +++ b/drivers/media/pci/ivtv/ivtv-driver.h @@ -64,8 +64,8 @@ #include <media/v4l2-device.h> #include <media/v4l2-fh.h> #include <media/tuner.h> -#include <media/cx2341x.h> -#include <media/ir-kbd-i2c.h> +#include <media/drv-intf/cx2341x.h> +#include <media/i2c/ir-kbd-i2c.h> #include <linux/ivtv.h> diff --git a/drivers/media/pci/ivtv/ivtv-fileops.c b/drivers/media/pci/ivtv/ivtv-fileops.c index 605d280d8..c9bd018e5 100644 --- a/drivers/media/pci/ivtv/ivtv-fileops.c +++ b/drivers/media/pci/ivtv/ivtv-fileops.c @@ -34,7 +34,7 @@ #include "ivtv-cards.h" #include "ivtv-firmware.h" #include <media/v4l2-event.h> -#include <media/saa7115.h> +#include <media/i2c/saa7115.h> /* This function tries to claim the stream for a specific file descriptor. If no one else is using this stream then the stream is claimed and diff --git a/drivers/media/pci/ivtv/ivtv-firmware.c b/drivers/media/pci/ivtv/ivtv-firmware.c index a9b8e9905..754556851 100644 --- a/drivers/media/pci/ivtv/ivtv-firmware.c +++ b/drivers/media/pci/ivtv/ivtv-firmware.c @@ -26,7 +26,7 @@ #include "ivtv-ioctl.h" #include "ivtv-cards.h" #include <linux/firmware.h> -#include <media/saa7127.h> +#include <media/i2c/saa7127.h> #define IVTV_MASK_SPU_ENABLE 0xFFFFFFFE #define IVTV_MASK_VPU_ENABLE15 0xFFFFFFF6 diff --git a/drivers/media/pci/ivtv/ivtv-i2c.c b/drivers/media/pci/ivtv/ivtv-i2c.c index 1a41ba5c7..bccbf2d18 100644 --- a/drivers/media/pci/ivtv/ivtv-i2c.c +++ b/drivers/media/pci/ivtv/ivtv-i2c.c @@ -63,7 +63,7 @@ #include "ivtv-cards.h" #include "ivtv-gpio.h" #include "ivtv-i2c.h" -#include <media/cx25840.h> +#include <media/drv-intf/cx25840.h> /* i2c implementation for cx23415/6 chip, ivtv project. * Author: Kevin Thayer (nufan_wfk at yahoo.com) diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.c b/drivers/media/pci/ivtv/ivtv-ioctl.c index 9a21c17fc..2dc4b20f3 100644 --- a/drivers/media/pci/ivtv/ivtv-ioctl.c +++ b/drivers/media/pci/ivtv/ivtv-ioctl.c @@ -32,7 +32,7 @@ #include "ivtv-gpio.h" #include "ivtv-controls.h" #include "ivtv-cards.h" -#include <media/saa7127.h> +#include <media/i2c/saa7127.h> #include <media/tveeprom.h> #include <media/v4l2-event.h> #include <linux/dvb/audio.h> @@ -831,11 +831,11 @@ static int ivtv_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cropca struct ivtv *itv = id->itv; if (cropcap->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - cropcap->pixelaspect.numerator = itv->is_50hz ? 59 : 10; - cropcap->pixelaspect.denominator = itv->is_50hz ? 54 : 11; + cropcap->pixelaspect.numerator = itv->is_50hz ? 54 : 11; + cropcap->pixelaspect.denominator = itv->is_50hz ? 59 : 10; } else if (cropcap->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { - cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10; - cropcap->pixelaspect.denominator = itv->is_out_50hz ? 54 : 11; + cropcap->pixelaspect.numerator = itv->is_out_50hz ? 54 : 11; + cropcap->pixelaspect.denominator = itv->is_out_50hz ? 59 : 10; } else { return -EINVAL; } diff --git a/drivers/media/pci/ivtv/ivtv-routing.c b/drivers/media/pci/ivtv/ivtv-routing.c index 8898c569a..0c168f238 100644 --- a/drivers/media/pci/ivtv/ivtv-routing.c +++ b/drivers/media/pci/ivtv/ivtv-routing.c @@ -24,10 +24,10 @@ #include "ivtv-gpio.h" #include "ivtv-routing.h" -#include <media/msp3400.h> -#include <media/m52790.h> -#include <media/upd64031a.h> -#include <media/upd64083.h> +#include <media/drv-intf/msp3400.h> +#include <media/i2c/m52790.h> +#include <media/i2c/upd64031a.h> +#include <media/i2c/upd64083.h> /* Selects the audio input and output according to the current settings. */ diff --git a/drivers/media/pci/netup_unidvb/netup_unidvb_core.c b/drivers/media/pci/netup_unidvb/netup_unidvb_core.c index 3fdbd81b5..525ebfefe 100644 --- a/drivers/media/pci/netup_unidvb/netup_unidvb_core.c +++ b/drivers/media/pci/netup_unidvb/netup_unidvb_core.c @@ -277,7 +277,6 @@ static irqreturn_t netup_unidvb_isr(int irq, void *dev_id) } static int netup_unidvb_queue_setup(struct vb2_queue *vq, - const void *parg, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], @@ -388,7 +387,7 @@ static int netup_unidvb_dvb_init(struct netup_unidvb_dev *ndev, vb2_dvb_alloc_frontend( &ndev->frontends[num], 3) == NULL) { dev_dbg(&ndev->pci_dev->dev, - "%s(): unable to to alllocate vb2_dvb_frontend\n", + "%s(): unable to allocate vb2_dvb_frontend\n", __func__); return -ENOMEM; } @@ -580,7 +579,7 @@ static void netup_unidvb_dma_worker(struct work_struct *work) dev_dbg(&ndev->pci_dev->dev, "%s(): buffer %p done, size %d\n", __func__, buf, buf->size); - v4l2_get_timestamp(&buf->vb.timestamp); + buf->vb.vb2_buf.timestamp = ktime_get_ns(); vb2_set_plane_payload(&buf->vb.vb2_buf, 0, buf->size); vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE); } diff --git a/drivers/media/pci/ngene/ngene-core.c b/drivers/media/pci/ngene/ngene-core.c index 4c3774af2..47232ca51 100644 --- a/drivers/media/pci/ngene/ngene-core.c +++ b/drivers/media/pci/ngene/ngene-core.c @@ -1513,7 +1513,7 @@ static int init_channel(struct ngene_channel *chan) set_transfer(&chan->dev->channel[2], 1); dvb_register_device(adapter, &chan->ci_dev, &ngene_dvbdev_ci, (void *) chan, - DVB_DEVICE_SEC); + DVB_DEVICE_SEC, 0); if (!chan->ci_dev) goto err; } diff --git a/drivers/media/pci/saa7134/saa7134-core.c b/drivers/media/pci/saa7134/saa7134-core.c index f720cea80..e227b02cc 100644 --- a/drivers/media/pci/saa7134/saa7134-core.c +++ b/drivers/media/pci/saa7134/saa7134-core.c @@ -309,7 +309,7 @@ void saa7134_buffer_finish(struct saa7134_dev *dev, core_dbg("buffer_finish %p\n", q->curr); /* finish current buffer */ - v4l2_get_timestamp(&q->curr->vb2.timestamp); + q->curr->vb2.vb2_buf.timestamp = ktime_get_ns(); q->curr->vb2.sequence = q->seq_nr++; vb2_buffer_done(&q->curr->vb2.vb2_buf, state); q->curr = NULL; diff --git a/drivers/media/pci/saa7134/saa7134-ts.c b/drivers/media/pci/saa7134/saa7134-ts.c index 7fb5ee7e2..0584a2adb 100644 --- a/drivers/media/pci/saa7134/saa7134-ts.c +++ b/drivers/media/pci/saa7134/saa7134-ts.c @@ -116,7 +116,7 @@ int saa7134_ts_buffer_prepare(struct vb2_buffer *vb2) } EXPORT_SYMBOL_GPL(saa7134_ts_buffer_prepare); -int saa7134_ts_queue_setup(struct vb2_queue *q, const void *parg, +int saa7134_ts_queue_setup(struct vb2_queue *q, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) { diff --git a/drivers/media/pci/saa7134/saa7134-vbi.c b/drivers/media/pci/saa7134/saa7134-vbi.c index 6271b0eb0..e76da37c4 100644 --- a/drivers/media/pci/saa7134/saa7134-vbi.c +++ b/drivers/media/pci/saa7134/saa7134-vbi.c @@ -138,7 +138,7 @@ static int buffer_prepare(struct vb2_buffer *vb2) saa7134_buffer_startpage(buf)); } -static int queue_setup(struct vb2_queue *q, const void *parg, +static int queue_setup(struct vb2_queue *q, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) { diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index 518086c7a..a63c1366a 100644 --- a/drivers/media/pci/saa7134/saa7134-video.c +++ b/drivers/media/pci/saa7134/saa7134-video.c @@ -32,7 +32,7 @@ #include <media/v4l2-common.h> #include <media/v4l2-event.h> -#include <media/saa6588.h> +#include <media/i2c/saa6588.h> /* ------------------------------------------------------------------ */ @@ -904,7 +904,7 @@ static int buffer_prepare(struct vb2_buffer *vb2) saa7134_buffer_startpage(buf)); } -static int queue_setup(struct vb2_queue *q, const void *parg, +static int queue_setup(struct vb2_queue *q, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) { diff --git a/drivers/media/pci/saa7134/saa7134.h b/drivers/media/pci/saa7134/saa7134.h index 6b6d234f5..5938bc781 100644 --- a/drivers/media/pci/saa7134/saa7134.h +++ b/drivers/media/pci/saa7134/saa7134.h @@ -42,7 +42,7 @@ #include <media/v4l2-ctrls.h> #include <media/tuner.h> #include <media/rc-core.h> -#include <media/ir-kbd-i2c.h> +#include <media/i2c/ir-kbd-i2c.h> #include <media/videobuf2-dma-sg.h> #include <sound/core.h> #include <sound/pcm.h> @@ -820,7 +820,7 @@ void saa7134_video_fini(struct saa7134_dev *dev); int saa7134_ts_buffer_init(struct vb2_buffer *vb2); int saa7134_ts_buffer_prepare(struct vb2_buffer *vb2); -int saa7134_ts_queue_setup(struct vb2_queue *q, const void *parg, +int saa7134_ts_queue_setup(struct vb2_queue *q, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]); int saa7134_ts_start_streaming(struct vb2_queue *vq, unsigned int count); diff --git a/drivers/media/pci/saa7146/hexium_gemini.c b/drivers/media/pci/saa7146/hexium_gemini.c index 03cbcd209..c889ec9f8 100644 --- a/drivers/media/pci/saa7146/hexium_gemini.c +++ b/drivers/media/pci/saa7146/hexium_gemini.c @@ -25,7 +25,7 @@ #define DEBUG_VARIABLE debug -#include <media/saa7146_vv.h> +#include <media/drv-intf/saa7146_vv.h> #include <linux/module.h> static int debug; diff --git a/drivers/media/pci/saa7146/hexium_orion.c b/drivers/media/pci/saa7146/hexium_orion.c index 15f0d66ff..c306a92e8 100644 --- a/drivers/media/pci/saa7146/hexium_orion.c +++ b/drivers/media/pci/saa7146/hexium_orion.c @@ -25,7 +25,7 @@ #define DEBUG_VARIABLE debug -#include <media/saa7146_vv.h> +#include <media/drv-intf/saa7146_vv.h> #include <linux/module.h> static int debug; diff --git a/drivers/media/pci/saa7146/mxb.c b/drivers/media/pci/saa7146/mxb.c index 0ca1e07ae..504d78807 100644 --- a/drivers/media/pci/saa7146/mxb.c +++ b/drivers/media/pci/saa7146/mxb.c @@ -25,10 +25,10 @@ #define DEBUG_VARIABLE debug -#include <media/saa7146_vv.h> +#include <media/drv-intf/saa7146_vv.h> #include <media/tuner.h> #include <media/v4l2-common.h> -#include <media/saa7115.h> +#include <media/i2c/saa7115.h> #include <linux/module.h> #include "tea6415c.h" diff --git a/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c index 4432fd69b..67a14c41c 100644 --- a/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c +++ b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c @@ -531,8 +531,7 @@ static int solo_enc_fillbuf(struct solo_enc_dev *solo_enc, if (!ret) { vbuf->sequence = solo_enc->sequence++; - vbuf->timestamp.tv_sec = vop_sec(vh); - vbuf->timestamp.tv_usec = vop_usec(vh); + vb->timestamp = ktime_get_ns(); /* Check for motion flags */ if (solo_is_motion_on(solo_enc) && enc_buf->motion) { @@ -663,7 +662,6 @@ static int solo_ring_thread(void *data) } static int solo_enc_queue_setup(struct vb2_queue *q, - const void *parg, unsigned int *num_buffers, unsigned int *num_planes, unsigned int sizes[], void *alloc_ctxs[]) diff --git a/drivers/media/pci/solo6x10/solo6x10-v4l2.c b/drivers/media/pci/solo6x10/solo6x10-v4l2.c index f7ce493b1..721ff5320 100644 --- a/drivers/media/pci/solo6x10/solo6x10-v4l2.c +++ b/drivers/media/pci/solo6x10/solo6x10-v4l2.c @@ -225,7 +225,7 @@ finish_buf: vb2_set_plane_payload(vb, 0, solo_vlines(solo_dev) * solo_bytesperline(solo_dev)); vbuf->sequence = solo_dev->sequence++; - v4l2_get_timestamp(&vbuf->timestamp); + vb->timestamp = ktime_get_ns(); } vb2_buffer_done(vb, error ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); @@ -313,7 +313,7 @@ static void solo_stop_thread(struct solo_dev *solo_dev) solo_dev->kthread = NULL; } -static int solo_queue_setup(struct vb2_queue *q, const void *parg, +static int solo_queue_setup(struct vb2_queue *q, unsigned int *num_buffers, unsigned int *num_planes, unsigned int sizes[], void *alloc_ctxs[]) { diff --git a/drivers/media/pci/sta2x11/sta2x11_vip.c b/drivers/media/pci/sta2x11/sta2x11_vip.c index 6367b455a..753411cbb 100644 --- a/drivers/media/pci/sta2x11/sta2x11_vip.c +++ b/drivers/media/pci/sta2x11/sta2x11_vip.c @@ -265,7 +265,7 @@ static void vip_active_buf_next(struct sta2x11_vip *vip) /* Videobuf2 Operations */ -static int queue_setup(struct vb2_queue *vq, const void *parg, +static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) { @@ -817,7 +817,7 @@ static irqreturn_t vip_irq(int irq, struct sta2x11_vip *vip) /* Disable acquisition */ reg_write(vip, DVP_CTL, reg_read(vip, DVP_CTL) & ~DVP_CTL_ENA); /* Remove the active buffer from the list */ - v4l2_get_timestamp(&vip->active->vb.timestamp); + vip->active->vb.vb2_buf.timestamp = ktime_get_ns(); vip->active->vb.sequence = vip->sequence++; vb2_buffer_done(&vip->active->vb.vb2_buf, VB2_BUF_STATE_DONE); } diff --git a/drivers/media/pci/ttpci/av7110.c b/drivers/media/pci/ttpci/av7110.c index 93af09989..dd1a18e59 100644 --- a/drivers/media/pci/ttpci/av7110.c +++ b/drivers/media/pci/ttpci/av7110.c @@ -26,7 +26,7 @@ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * * - * the project's page is at http://www.linuxtv.org/ + * the project's page is at https://linuxtv.org */ @@ -1358,7 +1358,7 @@ static int av7110_register(struct av7110 *av7110) #ifdef CONFIG_DVB_AV7110_OSD dvb_register_device(&av7110->dvb_adapter, &av7110->osd_dev, - &dvbdev_osd, av7110, DVB_DEVICE_OSD); + &dvbdev_osd, av7110, DVB_DEVICE_OSD, 0); #endif dvb_net_init(&av7110->dvb_adapter, &av7110->dvb_net, &dvbdemux->dmx); @@ -1537,7 +1537,7 @@ static int get_firmware(struct av7110* av7110) printk(KERN_ERR "dvb-ttpci: usually this should be in " "/usr/lib/hotplug/firmware or /lib/firmware\n"); printk(KERN_ERR "dvb-ttpci: and can be downloaded from" - " http://www.linuxtv.org/download/dvb/firmware/\n"); + " https://linuxtv.org/download/dvb/firmware/\n"); } else printk(KERN_ERR "dvb-ttpci: cannot request firmware" " (error %i)\n", ret); @@ -2314,7 +2314,7 @@ static int frontend_init(struct av7110 *av7110) /* Budgetpatch note: * Original hardware design by Roberto Deza: * There is a DVB_Wiki at - * http://www.linuxtv.org/ + * https://linuxtv.org * * New software triggering design by Emard that works on * original Roberto Deza's hardware: diff --git a/drivers/media/pci/ttpci/av7110.h b/drivers/media/pci/ttpci/av7110.h index 3a55927ed..3707ccd02 100644 --- a/drivers/media/pci/ttpci/av7110.h +++ b/drivers/media/pci/ttpci/av7110.h @@ -32,7 +32,7 @@ #include "stv0297.h" #include "l64781.h" -#include <media/saa7146_vv.h> +#include <media/drv-intf/saa7146_vv.h> #define ANALOG_TUNER_VES1820 1 diff --git a/drivers/media/pci/ttpci/av7110_av.c b/drivers/media/pci/ttpci/av7110_av.c index 9ed1ec7d3..26c5696c1 100644 --- a/drivers/media/pci/ttpci/av7110_av.c +++ b/drivers/media/pci/ttpci/av7110_av.c @@ -25,7 +25,7 @@ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * * - * the project's page is at http://www.linuxtv.org/ + * the project's page is at https://linuxtv.org */ #include <linux/types.h> @@ -280,9 +280,11 @@ int av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen) } -int av7110_set_volume(struct av7110 *av7110, int volleft, int volright) +int av7110_set_volume(struct av7110 *av7110, unsigned int volleft, + unsigned int volright) { - int err, vol, val, balance = 0; + unsigned int vol, val, balance = 0; + int err; dprintk(2, "av7110:%p, \n", av7110); @@ -1043,6 +1045,9 @@ static int play_iframe(struct av7110 *av7110, char __user *buf, unsigned int len dprintk(2, "av7110:%p, \n", av7110); + if (len == 0) + return 0; + if (!(av7110->playing & RP_VIDEO)) { if (av7110_av_start_play(av7110, RP_VIDEO) < 0) return -EBUSY; @@ -1589,10 +1594,10 @@ int av7110_av_register(struct av7110 *av7110) memset(&av7110->video_size, 0, sizeof (video_size_t)); dvb_register_device(&av7110->dvb_adapter, &av7110->video_dev, - &dvbdev_video, av7110, DVB_DEVICE_VIDEO); + &dvbdev_video, av7110, DVB_DEVICE_VIDEO, 0); dvb_register_device(&av7110->dvb_adapter, &av7110->audio_dev, - &dvbdev_audio, av7110, DVB_DEVICE_AUDIO); + &dvbdev_audio, av7110, DVB_DEVICE_AUDIO, 0); return 0; } diff --git a/drivers/media/pci/ttpci/av7110_av.h b/drivers/media/pci/ttpci/av7110_av.h index 5f02ef85e..f52276f47 100644 --- a/drivers/media/pci/ttpci/av7110_av.h +++ b/drivers/media/pci/ttpci/av7110_av.h @@ -10,7 +10,8 @@ extern int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len); extern int av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen); extern int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t len); -extern int av7110_set_volume(struct av7110 *av7110, int volleft, int volright); +extern int av7110_set_volume(struct av7110 *av7110, unsigned int volleft, + unsigned int volright); extern int av7110_av_stop(struct av7110 *av7110, int av); extern int av7110_av_start_record(struct av7110 *av7110, int av, struct dvb_demux_feed *dvbdmxfeed); diff --git a/drivers/media/pci/ttpci/av7110_ca.c b/drivers/media/pci/ttpci/av7110_ca.c index a6079b902..96a130fb4 100644 --- a/drivers/media/pci/ttpci/av7110_ca.c +++ b/drivers/media/pci/ttpci/av7110_ca.c @@ -25,7 +25,7 @@ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * * - * the project's page is at http://www.linuxtv.org/ + * the project's page is at https://linuxtv.org */ #include <linux/kernel.h> @@ -378,7 +378,7 @@ static struct dvb_device dvbdev_ca = { int av7110_ca_register(struct av7110 *av7110) { return dvb_register_device(&av7110->dvb_adapter, &av7110->ca_dev, - &dvbdev_ca, av7110, DVB_DEVICE_CA); + &dvbdev_ca, av7110, DVB_DEVICE_CA, 0); } void av7110_ca_unregister(struct av7110 *av7110) diff --git a/drivers/media/pci/ttpci/av7110_hw.c b/drivers/media/pci/ttpci/av7110_hw.c index 300bd3c94..0583d56ef 100644 --- a/drivers/media/pci/ttpci/av7110_hw.c +++ b/drivers/media/pci/ttpci/av7110_hw.c @@ -22,7 +22,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * - * the project's page is at http://www.linuxtv.org/ + * the project's page is at https://linuxtv.org */ /* for debugging ARM communication: */ diff --git a/drivers/media/pci/ttpci/av7110_v4l.c b/drivers/media/pci/ttpci/av7110_v4l.c index 6c4076acb..479aff02d 100644 --- a/drivers/media/pci/ttpci/av7110_v4l.c +++ b/drivers/media/pci/ttpci/av7110_v4l.c @@ -22,7 +22,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * - * the project's page is at http://www.linuxtv.org/ + * the project's page is at https://linuxtv.org */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/media/pci/ttpci/budget-av.c b/drivers/media/pci/ttpci/budget-av.c index 009fe2bf0..15bcb0842 100644 --- a/drivers/media/pci/ttpci/budget-av.c +++ b/drivers/media/pci/ttpci/budget-av.c @@ -30,7 +30,7 @@ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * * - * the project's page is at http://www.linuxtv.org/ + * the project's page is at https://linuxtv.org */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -46,7 +46,7 @@ #include "tda1004x.h" #include "tua6100.h" #include "dvb-pll.h" -#include <media/saa7146_vv.h> +#include <media/drv-intf/saa7146_vv.h> #include <linux/module.h> #include <linux/errno.h> #include <linux/slab.h> diff --git a/drivers/media/pci/ttpci/budget-ci.c b/drivers/media/pci/ttpci/budget-ci.c index f8d4e710f..f01d1459e 100644 --- a/drivers/media/pci/ttpci/budget-ci.c +++ b/drivers/media/pci/ttpci/budget-ci.c @@ -26,7 +26,7 @@ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * * - * the project's page is at http://www.linuxtv.org/ + * the project's page is at https://linuxtv.org */ #include <linux/module.h> diff --git a/drivers/media/pci/ttpci/budget-core.c b/drivers/media/pci/ttpci/budget-core.c index e9674b400..6d42dcfd4 100644 --- a/drivers/media/pci/ttpci/budget-core.c +++ b/drivers/media/pci/ttpci/budget-core.c @@ -31,7 +31,7 @@ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * * - * the project's page is at http://www.linuxtv.org/ + * the project's page is at https://linuxtv.org */ diff --git a/drivers/media/pci/ttpci/budget-patch.c b/drivers/media/pci/ttpci/budget-patch.c index b5b65962c..591dbdfa2 100644 --- a/drivers/media/pci/ttpci/budget-patch.c +++ b/drivers/media/pci/ttpci/budget-patch.c @@ -27,7 +27,7 @@ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * * - * the project's page is at http://www.linuxtv.org/ + * the project's page is at https://linuxtv.org */ #include "av7110.h" diff --git a/drivers/media/pci/ttpci/budget.c b/drivers/media/pci/ttpci/budget.c index 2eaf748b5..6f79bed5f 100644 --- a/drivers/media/pci/ttpci/budget.c +++ b/drivers/media/pci/ttpci/budget.c @@ -31,7 +31,7 @@ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * * - * the project's page is at http://www.linuxtv.org/ + * the project's page is at https://linuxtv.org */ #include "budget.h" diff --git a/drivers/media/pci/ttpci/budget.h b/drivers/media/pci/ttpci/budget.h index 1ccbe1a49..655eef523 100644 --- a/drivers/media/pci/ttpci/budget.h +++ b/drivers/media/pci/ttpci/budget.h @@ -13,7 +13,7 @@ #include <linux/module.h> #include <linux/mutex.h> -#include <media/saa7146.h> +#include <media/drv-intf/saa7146.h> extern int budget_debug; diff --git a/drivers/media/pci/tw68/tw68-video.c b/drivers/media/pci/tw68/tw68-video.c index 46642ef91..07116a87a 100644 --- a/drivers/media/pci/tw68/tw68-video.c +++ b/drivers/media/pci/tw68/tw68-video.c @@ -376,28 +376,28 @@ static int tw68_buffer_count(unsigned int size, unsigned int count) /* ------------------------------------------------------------- */ /* vb2 queue operations */ -static int tw68_queue_setup(struct vb2_queue *q, const void *parg, +static int tw68_queue_setup(struct vb2_queue *q, unsigned int *num_buffers, unsigned int *num_planes, unsigned int sizes[], void *alloc_ctxs[]) { - const struct v4l2_format *fmt = parg; struct tw68_dev *dev = vb2_get_drv_priv(q); unsigned tot_bufs = q->num_buffers + *num_buffers; + unsigned size = (dev->fmt->depth * dev->width * dev->height) >> 3; - sizes[0] = (dev->fmt->depth * dev->width * dev->height) >> 3; + if (tot_bufs < 2) + tot_bufs = 2; + tot_bufs = tw68_buffer_count(size, tot_bufs); + *num_buffers = tot_bufs - q->num_buffers; alloc_ctxs[0] = dev->alloc_ctx; /* - * We allow create_bufs, but only if the sizeimage is the same as the + * We allow create_bufs, but only if the sizeimage is >= as the * current sizeimage. The tw68_buffer_count calculation becomes quite * difficult otherwise. */ - if (fmt && fmt->fmt.pix.sizeimage < sizes[0]) - return -EINVAL; + if (*num_planes) + return sizes[0] < size ? -EINVAL : 0; *num_planes = 1; - if (tot_bufs < 2) - tot_bufs = 2; - tot_bufs = tw68_buffer_count(sizes[0], tot_bufs); - *num_buffers = tot_bufs - q->num_buffers; + sizes[0] = size; return 0; } @@ -1016,7 +1016,7 @@ void tw68_irq_video_done(struct tw68_dev *dev, unsigned long status) buf = list_entry(dev->active.next, struct tw68_buf, list); list_del(&buf->list); spin_unlock(&dev->slock); - v4l2_get_timestamp(&buf->vb.timestamp); + buf->vb.vb2_buf.timestamp = ktime_get_ns(); buf->vb.field = dev->field; buf->vb.sequence = dev->seqnr++; vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE); diff --git a/drivers/media/pci/zoran/zoran_card.c b/drivers/media/pci/zoran/zoran_card.c index 1136d92af..9d2697f5b 100644 --- a/drivers/media/pci/zoran/zoran_card.c +++ b/drivers/media/pci/zoran/zoran_card.c @@ -50,7 +50,7 @@ #include <linux/mutex.h> #include <linux/io.h> #include <media/v4l2-common.h> -#include <media/bt819.h> +#include <media/i2c/bt819.h> #include "videocodec.h" #include "zoran.h" diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index ccbc9742c..8b89ebe16 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -38,7 +38,7 @@ config VIDEO_SH_VOU depends on MEDIA_CAMERA_SUPPORT depends on VIDEO_DEV && I2C && HAS_DMA depends on ARCH_SHMOBILE || COMPILE_TEST - select VIDEOBUF_DMA_CONTIG + select VIDEOBUF2_DMA_CONTIG help Support for the Video Output Unit (VOU) on SuperH SoCs. @@ -215,8 +215,8 @@ config VIDEO_SAMSUNG_EXYNOS_GSC config VIDEO_STI_BDISP tristate "STMicroelectronics BDISP 2D blitter driver" depends on VIDEO_DEV && VIDEO_V4L2 + depends on HAS_DMA depends on ARCH_STI || COMPILE_TEST - depends on HAVE_DMA_ATTRS select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV help diff --git a/drivers/media/platform/am437x/am437x-vpfe.c b/drivers/media/platform/am437x/am437x-vpfe.c index f0480d687..de32e3a3d 100644 --- a/drivers/media/platform/am437x/am437x-vpfe.c +++ b/drivers/media/platform/am437x/am437x-vpfe.c @@ -1281,7 +1281,7 @@ static inline void vpfe_schedule_bottom_field(struct vpfe_device *vpfe) */ static inline void vpfe_process_buffer_complete(struct vpfe_device *vpfe) { - v4l2_get_timestamp(&vpfe->cur_frm->vb.timestamp); + vpfe->cur_frm->vb.vb2_buf.timestamp = ktime_get_ns(); vpfe->cur_frm->vb.field = vpfe->fmt.fmt.pix.field; vpfe->cur_frm->vb.sequence = vpfe->sequence++; vb2_buffer_done(&vpfe->cur_frm->vb.vb2_buf, VB2_BUF_STATE_DONE); @@ -1898,7 +1898,6 @@ static void vpfe_calculate_offsets(struct vpfe_device *vpfe) /* * vpfe_queue_setup - Callback function for buffer setup. * @vq: vb2_queue ptr - * @fmt: v4l2 format * @nbuffers: ptr to number of buffers requested by application * @nplanes:: contains number of distinct video planes needed to hold a frame * @sizes[]: contains the size (in bytes) of each plane. @@ -1908,22 +1907,24 @@ static void vpfe_calculate_offsets(struct vpfe_device *vpfe) * the buffer count and buffer size */ static int vpfe_queue_setup(struct vb2_queue *vq, - const void *parg, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) { - const struct v4l2_format *fmt = parg; struct vpfe_device *vpfe = vb2_get_drv_priv(vq); - - if (fmt && fmt->fmt.pix.sizeimage < vpfe->fmt.fmt.pix.sizeimage) - return -EINVAL; + unsigned size = vpfe->fmt.fmt.pix.sizeimage; if (vq->num_buffers + *nbuffers < 3) *nbuffers = 3 - vq->num_buffers; + alloc_ctxs[0] = vpfe->alloc_ctx; + + if (*nplanes) { + if (sizes[0] < size) + return -EINVAL; + size = sizes[0]; + } *nplanes = 1; - sizes[0] = fmt ? fmt->fmt.pix.sizeimage : vpfe->fmt.fmt.pix.sizeimage; - alloc_ctxs[0] = vpfe->alloc_ctx; + sizes[0] = size; vpfe_dbg(1, vpfe, "nbuffers=%d, size=%u\n", *nbuffers, sizes[0]); diff --git a/drivers/media/platform/blackfin/bfin_capture.c b/drivers/media/platform/blackfin/bfin_capture.c index 7764b9c48..d0092dae7 100644 --- a/drivers/media/platform/blackfin/bfin_capture.c +++ b/drivers/media/platform/blackfin/bfin_capture.c @@ -202,22 +202,20 @@ static void bcap_free_sensor_formats(struct bcap_device *bcap_dev) } static int bcap_queue_setup(struct vb2_queue *vq, - const void *parg, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) { - const struct v4l2_format *fmt = parg; struct bcap_device *bcap_dev = vb2_get_drv_priv(vq); - if (fmt && fmt->fmt.pix.sizeimage < bcap_dev->fmt.sizeimage) - return -EINVAL; - if (vq->num_buffers + *nbuffers < 2) *nbuffers = 2; + alloc_ctxs[0] = bcap_dev->alloc_ctx; + + if (*nplanes) + return sizes[0] < bcap_dev->fmt.sizeimage ? -EINVAL : 0; *nplanes = 1; - sizes[0] = fmt ? fmt->fmt.pix.sizeimage : bcap_dev->fmt.sizeimage; - alloc_ctxs[0] = bcap_dev->alloc_ctx; + sizes[0] = bcap_dev->fmt.sizeimage; return 0; } @@ -406,7 +404,7 @@ static irqreturn_t bcap_isr(int irq, void *dev_id) spin_lock(&bcap_dev->lock); if (!list_empty(&bcap_dev->dma_queue)) { - v4l2_get_timestamp(&vbuf->timestamp); + vb->timestamp = ktime_get_ns(); if (ppi->err) { vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); ppi->err = false; diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 654e964f8..7d28899f8 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -246,7 +246,7 @@ void coda_fill_bitstream(struct coda_ctx *ctx, bool streaming) /* Drop frames that do not start/end with a SOI/EOI markers */ if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG && - !coda_jpeg_check_buffer(ctx, src_buf)) { + !coda_jpeg_check_buffer(ctx, &src_buf->vb2_buf)) { v4l2_err(&ctx->dev->v4l2_dev, "dropping invalid JPEG frame %d\n", ctx->qsequence); @@ -279,7 +279,7 @@ void coda_fill_bitstream(struct coda_ctx *ctx, bool streaming) if (meta) { meta->sequence = src_buf->sequence; meta->timecode = src_buf->timecode; - meta->timestamp = src_buf->timestamp; + meta->timestamp = src_buf->vb2_buf.timestamp; meta->start = start; meta->end = ctx->bitstream_fifo.kfifo.in & ctx->bitstream_fifo.kfifo.mask; @@ -1364,7 +1364,7 @@ static void coda_finish_encode(struct coda_ctx *ctx) dst_buf->flags &= ~V4L2_BUF_FLAG_KEYFRAME; } - dst_buf->timestamp = src_buf->timestamp; + dst_buf->vb2_buf.timestamp = src_buf->vb2_buf.timestamp; dst_buf->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; dst_buf->flags |= src_buf->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK; @@ -2040,7 +2040,7 @@ static void coda_finish_decode(struct coda_ctx *ctx) dst_buf->flags |= ctx->frame_types[ctx->display_idx]; meta = &ctx->frame_metas[ctx->display_idx]; dst_buf->timecode = meta->timecode; - dst_buf->timestamp = meta->timestamp; + dst_buf->vb2_buf.timestamp = meta->timestamp; trace_coda_dec_rot_done(ctx, dst_buf, meta); diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 082bf54de..dafa1ab5c 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -28,7 +28,7 @@ #include <linux/slab.h> #include <linux/videodev2.h> #include <linux/of.h> -#include <linux/platform_data/coda.h> +#include <linux/platform_data/media/coda.h> #include <linux/reset.h> #include <media/v4l2-ctrls.h> @@ -131,6 +131,7 @@ static const struct coda_codec coda7_codecs[] = { CODA_CODEC(CODA7_MODE_ENCODE_MP4, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 1280, 720), CODA_CODEC(CODA7_MODE_ENCODE_MJPG, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_JPEG, 8192, 8192), CODA_CODEC(CODA7_MODE_DECODE_H264, V4L2_PIX_FMT_H264, V4L2_PIX_FMT_YUV420, 1920, 1088), + CODA_CODEC(CODA7_MODE_DECODE_MP2, V4L2_PIX_FMT_MPEG2, V4L2_PIX_FMT_YUV420, 1920, 1088), CODA_CODEC(CODA7_MODE_DECODE_MP4, V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_YUV420, 1920, 1088), CODA_CODEC(CODA7_MODE_DECODE_MJPG, V4L2_PIX_FMT_JPEG, V4L2_PIX_FMT_YUV420, 8192, 8192), }; @@ -139,6 +140,7 @@ static const struct coda_codec coda9_codecs[] = { CODA_CODEC(CODA9_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264, 1920, 1088), CODA_CODEC(CODA9_MODE_ENCODE_MP4, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 1920, 1088), CODA_CODEC(CODA9_MODE_DECODE_H264, V4L2_PIX_FMT_H264, V4L2_PIX_FMT_YUV420, 1920, 1088), + CODA_CODEC(CODA9_MODE_DECODE_MP2, V4L2_PIX_FMT_MPEG2, V4L2_PIX_FMT_YUV420, 1920, 1088), CODA_CODEC(CODA9_MODE_DECODE_MP4, V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_YUV420, 1920, 1088), }; @@ -187,6 +189,7 @@ static const struct coda_video_device coda_bit_decoder = { .ops = &coda_bit_decode_ops, .src_formats = { V4L2_PIX_FMT_H264, + V4L2_PIX_FMT_MPEG2, V4L2_PIX_FMT_MPEG4, }, .dst_formats = { @@ -293,7 +296,8 @@ static void coda_get_max_dimensions(struct coda_dev *dev, *max_h = h; } -const struct coda_video_device *to_coda_video_device(struct video_device *vdev) +static const struct coda_video_device *to_coda_video_device(struct video_device + *vdev) { struct coda_dev *dev = video_get_drvdata(vdev); unsigned int i = vdev - dev->vfd; @@ -469,6 +473,7 @@ static int coda_try_fmt(struct coda_ctx *ctx, const struct coda_codec *codec, /* fallthrough */ case V4L2_PIX_FMT_H264: case V4L2_PIX_FMT_MPEG4: + case V4L2_PIX_FMT_MPEG2: f->fmt.pix.bytesperline = 0; f->fmt.pix.sizeimage = coda_estimate_sizeimage(ctx, f->fmt.pix.sizeimage, @@ -920,6 +925,7 @@ static const struct v4l2_ioctl_ops coda_ioctl_ops = { .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, + .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, .vidioc_streamon = v4l2_m2m_ioctl_streamon, .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, @@ -1131,7 +1137,7 @@ static void set_default_params(struct coda_ctx *ctx) /* * Queue operations */ -static int coda_queue_setup(struct vb2_queue *vq, const void *parg, +static int coda_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) { @@ -1250,6 +1256,9 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) struct vb2_v4l2_buffer *buf; int ret = 0; + if (count < 1) + return -EINVAL; + q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { if (ctx->inst_type == CODA_INST_DECODER && ctx->use_bit) { @@ -1262,20 +1271,10 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) ret = -EINVAL; goto err; } - } else { - if (count < 1) { - ret = -EINVAL; - goto err; - } } ctx->streamon_out = 1; } else { - if (count < 1) { - ret = -EINVAL; - goto err; - } - ctx->streamon_cap = 1; } diff --git a/drivers/media/platform/coda/coda-jpeg.c b/drivers/media/platform/coda/coda-jpeg.c index 96cd42a0b..9f899a6ce 100644 --- a/drivers/media/platform/coda/coda-jpeg.c +++ b/drivers/media/platform/coda/coda-jpeg.c @@ -178,14 +178,28 @@ int coda_jpeg_write_tables(struct coda_ctx *ctx) return 0; } -bool coda_jpeg_check_buffer(struct coda_ctx *ctx, struct vb2_v4l2_buffer *vb) +bool coda_jpeg_check_buffer(struct coda_ctx *ctx, struct vb2_buffer *vb) { - void *vaddr = vb2_plane_vaddr(&vb->vb2_buf, 0); - u16 soi = be16_to_cpup((__be16 *)vaddr); - u16 eoi = be16_to_cpup((__be16 *)(vaddr + - vb2_get_plane_payload(&vb->vb2_buf, 0) - 2)); + void *vaddr = vb2_plane_vaddr(vb, 0); + u16 soi, eoi; + int len, i; + + soi = be16_to_cpup((__be16 *)vaddr); + if (soi != SOI_MARKER) + return false; + + len = vb2_get_plane_payload(vb, 0); + vaddr += len - 2; + for (i = 0; i < 32; i++) { + eoi = be16_to_cpup((__be16 *)(vaddr - i)); + if (eoi == EOI_MARKER) { + if (i > 0) + vb2_set_plane_payload(vb, 0, len - i); + return true; + } + } - return soi == SOI_MARKER && eoi == EOI_MARKER; + return false; } /* diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h index 96532b06b..d08e9843e 100644 --- a/drivers/media/platform/coda/coda.h +++ b/drivers/media/platform/coda/coda.h @@ -138,7 +138,7 @@ struct coda_buffer_meta { struct list_head list; u32 sequence; struct v4l2_timecode timecode; - struct timeval timestamp; + u64 timestamp; u32 start; u32 end; }; @@ -289,7 +289,7 @@ void coda_m2m_buf_done(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf, int coda_h264_padding(int size, char *p); -bool coda_jpeg_check_buffer(struct coda_ctx *ctx, struct vb2_v4l2_buffer *vb); +bool coda_jpeg_check_buffer(struct coda_ctx *ctx, struct vb2_buffer *vb); int coda_jpeg_write_tables(struct coda_ctx *ctx); void coda_set_jpeg_compression_quality(struct coda_ctx *ctx, int quality); diff --git a/drivers/media/platform/davinci/Kconfig b/drivers/media/platform/davinci/Kconfig index 469e9d28c..554e710de 100644 --- a/drivers/media/platform/davinci/Kconfig +++ b/drivers/media/platform/davinci/Kconfig @@ -3,6 +3,7 @@ config VIDEO_DAVINCI_VPIF_DISPLAY depends on VIDEO_V4L2 depends on ARCH_DAVINCI || COMPILE_TEST depends on HAS_DMA + depends on I2C select VIDEOBUF2_DMA_CONTIG select VIDEO_ADV7343 if MEDIA_SUBDRV_AUTOSELECT select VIDEO_THS7303 if MEDIA_SUBDRV_AUTOSELECT @@ -19,6 +20,7 @@ config VIDEO_DAVINCI_VPIF_CAPTURE depends on VIDEO_V4L2 depends on ARCH_DAVINCI || COMPILE_TEST depends on HAS_DMA + depends on I2C select VIDEOBUF2_DMA_CONTIG help Enables Davinci VPIF module used for capture devices. @@ -33,6 +35,7 @@ config VIDEO_DM6446_CCDC depends on VIDEO_V4L2 depends on ARCH_DAVINCI || COMPILE_TEST depends on HAS_DMA + depends on I2C select VIDEOBUF_DMA_CONTIG help Enables DaVinci CCD hw module. DaVinci CCDC hw interfaces @@ -49,6 +52,7 @@ config VIDEO_DM355_CCDC depends on VIDEO_V4L2 depends on ARCH_DAVINCI || COMPILE_TEST depends on HAS_DMA + depends on I2C select VIDEOBUF_DMA_CONTIG help Enables DM355 CCD hw module. DM355 CCDC hw interfaces @@ -64,6 +68,7 @@ config VIDEO_DM365_ISIF tristate "TI DM365 ISIF video capture driver" depends on VIDEO_V4L2 && ARCH_DAVINCI depends on HAS_DMA + depends on I2C select VIDEOBUF_DMA_CONTIG help Enables ISIF hw module. This is the hardware module for @@ -77,6 +82,7 @@ config VIDEO_DAVINCI_VPBE_DISPLAY tristate "TI DaVinci VPBE V4L2-Display driver" depends on VIDEO_V4L2 && ARCH_DAVINCI depends on HAS_DMA + depends on I2C select VIDEOBUF2_DMA_CONTIG help Enables Davinci VPBE module used for display devices. diff --git a/drivers/media/platform/davinci/vpbe_display.c b/drivers/media/platform/davinci/vpbe_display.c index 6d91422c4..0abcdfe97 100644 --- a/drivers/media/platform/davinci/vpbe_display.c +++ b/drivers/media/platform/davinci/vpbe_display.c @@ -74,7 +74,7 @@ static void vpbe_isr_even_field(struct vpbe_display *disp_obj, if (layer->cur_frm == layer->next_frm) return; - v4l2_get_timestamp(&layer->cur_frm->vb.timestamp); + layer->cur_frm->vb.vb2_buf.timestamp = ktime_get_ns(); vb2_buffer_done(&layer->cur_frm->vb.vb2_buf, VB2_BUF_STATE_DONE); /* Make cur_frm pointing to next_frm */ layer->cur_frm = layer->next_frm; @@ -228,28 +228,27 @@ static int vpbe_buffer_prepare(struct vb2_buffer *vb) * This function allocates memory for the buffers */ static int -vpbe_buffer_queue_setup(struct vb2_queue *vq, const void *parg, +vpbe_buffer_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) { - const struct v4l2_format *fmt = parg; /* Get the file handle object and layer object */ struct vpbe_layer *layer = vb2_get_drv_priv(vq); struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev; v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_buffer_setup\n"); - if (fmt && fmt->fmt.pix.sizeimage < layer->pix_fmt.sizeimage) - return -EINVAL; - /* Store number of buffers allocated in numbuffer member */ if (vq->num_buffers + *nbuffers < VPBE_DEFAULT_NUM_BUFS) *nbuffers = VPBE_DEFAULT_NUM_BUFS - vq->num_buffers; + alloc_ctxs[0] = layer->alloc_ctx; + + if (*nplanes) + return sizes[0] < layer->pix_fmt.sizeimage ? -EINVAL : 0; *nplanes = 1; - sizes[0] = fmt ? fmt->fmt.pix.sizeimage : layer->pix_fmt.sizeimage; - alloc_ctxs[0] = layer->alloc_ctx; + sizes[0] = layer->pix_fmt.sizeimage; return 0; } diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index c1e573b7c..08f7028c7 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -104,7 +104,6 @@ static int vpif_buffer_prepare(struct vb2_buffer *vb) /** * vpif_buffer_queue_setup : Callback function for buffer setup. * @vq: vb2_queue ptr - * @fmt: v4l2 format * @nbuffers: ptr to number of buffers requested by application * @nplanes:: contains number of distinct video planes needed to hold a frame * @sizes[]: contains the size (in bytes) of each plane. @@ -114,26 +113,26 @@ static int vpif_buffer_prepare(struct vb2_buffer *vb) * the buffer count and buffer size */ static int vpif_buffer_queue_setup(struct vb2_queue *vq, - const void *parg, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) { - const struct v4l2_format *fmt = parg; struct channel_obj *ch = vb2_get_drv_priv(vq); - struct common_obj *common; - - common = &ch->common[VPIF_VIDEO_INDEX]; + struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + unsigned size = common->fmt.fmt.pix.sizeimage; vpif_dbg(2, debug, "vpif_buffer_setup\n"); - if (fmt && fmt->fmt.pix.sizeimage < common->fmt.fmt.pix.sizeimage) - return -EINVAL; + if (*nplanes) { + if (sizes[0] < size) + return -EINVAL; + size = sizes[0]; + } if (vq->num_buffers + *nbuffers < 3) *nbuffers = 3 - vq->num_buffers; *nplanes = 1; - sizes[0] = fmt ? fmt->fmt.pix.sizeimage : common->fmt.fmt.pix.sizeimage; + sizes[0] = size; alloc_ctxs[0] = common->alloc_ctx; /* Calculate the offset for Y and C data in the buffer */ @@ -331,7 +330,7 @@ static struct vb2_ops video_qops = { */ static void vpif_process_buffer_complete(struct common_obj *common) { - v4l2_get_timestamp(&common->cur_frm->vb.timestamp); + common->cur_frm->vb.vb2_buf.timestamp = ktime_get_ns(); vb2_buffer_done(&common->cur_frm->vb.vb2_buf, VB2_BUF_STATE_DONE); /* Make curFrm pointing to nextFrm */ common->cur_frm = common->next_frm; diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c index fd2780306..f40755cf1 100644 --- a/drivers/media/platform/davinci/vpif_display.c +++ b/drivers/media/platform/davinci/vpif_display.c @@ -99,7 +99,6 @@ static int vpif_buffer_prepare(struct vb2_buffer *vb) /** * vpif_buffer_queue_setup : Callback function for buffer setup. * @vq: vb2_queue ptr - * @fmt: v4l2 format * @nbuffers: ptr to number of buffers requested by application * @nplanes:: contains number of distinct video planes needed to hold a frame * @sizes[]: contains the size (in bytes) of each plane. @@ -109,22 +108,24 @@ static int vpif_buffer_prepare(struct vb2_buffer *vb) * the buffer count and buffer size */ static int vpif_buffer_queue_setup(struct vb2_queue *vq, - const void *parg, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) { - const struct v4l2_format *fmt = parg; struct channel_obj *ch = vb2_get_drv_priv(vq); struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + unsigned size = common->fmt.fmt.pix.sizeimage; - if (fmt && fmt->fmt.pix.sizeimage < common->fmt.fmt.pix.sizeimage) - return -EINVAL; + if (*nplanes) { + if (sizes[0] < size) + return -EINVAL; + size = sizes[0]; + } if (vq->num_buffers + *nbuffers < 3) *nbuffers = 3 - vq->num_buffers; *nplanes = 1; - sizes[0] = fmt ? fmt->fmt.pix.sizeimage : common->fmt.fmt.pix.sizeimage; + sizes[0] = size; alloc_ctxs[0] = common->alloc_ctx; /* Calculate the offset for Y and C data in the buffer */ @@ -330,7 +331,7 @@ static void process_interlaced_mode(int fid, struct common_obj *common) /* one frame is displayed If next frame is * available, release cur_frm and move on */ /* Copy frame display time */ - v4l2_get_timestamp(&common->cur_frm->vb.timestamp); + common->cur_frm->vb.vb2_buf.timestamp = ktime_get_ns(); /* Change status of the cur_frm */ vb2_buffer_done(&common->cur_frm->vb.vb2_buf, VB2_BUF_STATE_DONE); @@ -386,8 +387,8 @@ static irqreturn_t vpif_channel_isr(int irq, void *dev_id) if (!channel_first_int[i][channel_id]) { /* Mark status of the cur_frm to * done and unlock semaphore on it */ - v4l2_get_timestamp( - &common->cur_frm->vb.timestamp); + common->cur_frm->vb.vb2_buf.timestamp = + ktime_get_ns(); vb2_buffer_done(&common->cur_frm->vb.vb2_buf, VB2_BUF_STATE_DONE); /* Make cur_frm pointing to next_frm */ diff --git a/drivers/media/platform/exynos-gsc/gsc-m2m.c b/drivers/media/platform/exynos-gsc/gsc-m2m.c index d82e717ac..93782f15b 100644 --- a/drivers/media/platform/exynos-gsc/gsc-m2m.c +++ b/drivers/media/platform/exynos-gsc/gsc-m2m.c @@ -86,7 +86,7 @@ void gsc_m2m_job_finish(struct gsc_ctx *ctx, int vb_state) dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); if (src_vb && dst_vb) { - dst_vb->timestamp = src_vb->timestamp; + dst_vb->vb2_buf.timestamp = src_vb->vb2_buf.timestamp; dst_vb->timecode = src_vb->timecode; dst_vb->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; dst_vb->flags |= @@ -125,7 +125,7 @@ static int gsc_get_bufs(struct gsc_ctx *ctx) if (ret) return ret; - dst_vb->timestamp = src_vb->timestamp; + dst_vb->vb2_buf.timestamp = src_vb->vb2_buf.timestamp; return 0; } @@ -212,7 +212,6 @@ put_device: } static int gsc_m2m_queue_setup(struct vb2_queue *vq, - const void *parg, unsigned int *num_buffers, unsigned int *num_planes, unsigned int sizes[], void *allocators[]) { diff --git a/drivers/media/platform/exynos4-is/Kconfig b/drivers/media/platform/exynos4-is/Kconfig index 40423c6c5..57d42c617 100644 --- a/drivers/media/platform/exynos4-is/Kconfig +++ b/drivers/media/platform/exynos4-is/Kconfig @@ -1,6 +1,6 @@ config VIDEO_SAMSUNG_EXYNOS4_IS - bool "Samsung S5P/EXYNOS4 SoC series Camera Subsystem driver" + tristate "Samsung S5P/EXYNOS4 SoC series Camera Subsystem driver" depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API depends on ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST depends on OF && COMMON_CLK diff --git a/drivers/media/platform/exynos4-is/common.c b/drivers/media/platform/exynos4-is/common.c index 0eb34ecb8..b90f5bb15 100644 --- a/drivers/media/platform/exynos4-is/common.c +++ b/drivers/media/platform/exynos4-is/common.c @@ -10,7 +10,7 @@ */ #include <linux/module.h> -#include <media/exynos-fimc.h> +#include <media/drv-intf/exynos-fimc.h> #include "common.h" /* Called with the media graph mutex held or entity->stream_count > 0. */ @@ -22,8 +22,7 @@ struct v4l2_subdev *fimc_find_remote_sensor(struct media_entity *entity) while (pad->flags & MEDIA_PAD_FL_SINK) { /* source pad */ pad = media_entity_remote_pad(pad); - if (pad == NULL || - media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) + if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) break; sd = media_entity_to_v4l2_subdev(pad->entity); diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c index 99e57320e..bf47d3b9c 100644 --- a/drivers/media/platform/exynos4-is/fimc-capture.c +++ b/drivers/media/platform/exynos4-is/fimc-capture.c @@ -193,7 +193,7 @@ void fimc_capture_irq_handler(struct fimc_dev *fimc, int deq_buf) test_bit(ST_CAPT_RUN, &fimc->state) && deq_buf) { v_buf = fimc_active_queue_pop(cap); - v4l2_get_timestamp(&v_buf->vb.timestamp); + v_buf->vb.vb2_buf.timestamp = ktime_get_ns(); v_buf->vb.sequence = cap->frame_count++; vb2_buffer_done(&v_buf->vb.vb2_buf, VB2_BUF_STATE_DONE); @@ -338,37 +338,36 @@ int fimc_capture_resume(struct fimc_dev *fimc) } -static int queue_setup(struct vb2_queue *vq, const void *parg, +static int queue_setup(struct vb2_queue *vq, unsigned int *num_buffers, unsigned int *num_planes, unsigned int sizes[], void *allocators[]) { - const struct v4l2_format *pfmt = parg; - const struct v4l2_pix_format_mplane *pixm = NULL; struct fimc_ctx *ctx = vq->drv_priv; struct fimc_frame *frame = &ctx->d_frame; struct fimc_fmt *fmt = frame->fmt; - unsigned long wh; + unsigned long wh = frame->f_width * frame->f_height; int i; - if (pfmt) { - pixm = &pfmt->fmt.pix_mp; - fmt = fimc_find_format(&pixm->pixelformat, NULL, - FMT_FLAGS_CAM | FMT_FLAGS_M2M, -1); - wh = pixm->width * pixm->height; - } else { - wh = frame->f_width * frame->f_height; - } - if (fmt == NULL) return -EINVAL; + if (*num_planes) { + if (*num_planes != fmt->memplanes) + return -EINVAL; + for (i = 0; i < *num_planes; i++) { + if (sizes[i] < (wh * fmt->depth[i]) / 8) + return -EINVAL; + allocators[i] = ctx->fimc_dev->alloc_ctx; + } + return 0; + } + *num_planes = fmt->memplanes; for (i = 0; i < fmt->memplanes; i++) { unsigned int size = (wh * fmt->depth[i]) / 8; - if (pixm) - sizes[i] = max(size, pixm->plane_fmt[i].sizeimage); - else if (fimc_fmt_is_user_defined(fmt->color)) + + if (fimc_fmt_is_user_defined(fmt->color)) sizes[i] = frame->payload[i]; else sizes[i] = max_t(u32, size, frame->payload[i]); @@ -1137,8 +1136,7 @@ static int fimc_pipeline_validate(struct fimc_dev *fimc) } } - if (src_pad == NULL || - media_entity_type(src_pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) + if (!src_pad || !is_media_entity_v4l2_subdev(src_pad->entity)) break; /* Don't call FIMC subdev operation to avoid nested locking */ @@ -1393,7 +1391,7 @@ static int fimc_link_setup(struct media_entity *entity, struct fimc_vid_cap *vc = &fimc->vid_cap; struct v4l2_subdev *sensor; - if (media_entity_type(remote->entity) != MEDIA_ENT_T_V4L2_SUBDEV) + if (!is_media_entity_v4l2_subdev(remote->entity)) return -EINVAL; if (WARN_ON(fimc == NULL)) @@ -1801,7 +1799,7 @@ static int fimc_register_capture_device(struct fimc_dev *fimc, vid_cap->wb_fmt.code = fmt->mbus_code; vid_cap->vd_pad.flags = MEDIA_PAD_FL_SINK; - ret = media_entity_init(&vfd->entity, 1, &vid_cap->vd_pad, 0); + ret = media_entity_pads_init(&vfd->entity, 1, &vid_cap->vd_pad); if (ret) goto err_free_ctx; @@ -1893,8 +1891,8 @@ int fimc_initialize_capture_subdev(struct fimc_dev *fimc) fimc->vid_cap.sd_pads[FIMC_SD_PAD_SINK_CAM].flags = MEDIA_PAD_FL_SINK; fimc->vid_cap.sd_pads[FIMC_SD_PAD_SINK_FIFO].flags = MEDIA_PAD_FL_SINK; fimc->vid_cap.sd_pads[FIMC_SD_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; - ret = media_entity_init(&sd->entity, FIMC_SD_PADS_NUM, - fimc->vid_cap.sd_pads, 0); + ret = media_entity_pads_init(&sd->entity, FIMC_SD_PADS_NUM, + fimc->vid_cap.sd_pads); if (ret) return ret; diff --git a/drivers/media/platform/exynos4-is/fimc-core.h b/drivers/media/platform/exynos4-is/fimc-core.h index d336fa291..6b7435453 100644 --- a/drivers/media/platform/exynos4-is/fimc-core.h +++ b/drivers/media/platform/exynos4-is/fimc-core.h @@ -27,7 +27,7 @@ #include <media/v4l2-device.h> #include <media/v4l2-mem2mem.h> #include <media/v4l2-mediabus.h> -#include <media/exynos-fimc.h> +#include <media/drv-intf/exynos-fimc.h> #define dbg(fmt, args...) \ pr_debug("%s:%d: " fmt "\n", __func__, __LINE__, ##args) diff --git a/drivers/media/platform/exynos4-is/fimc-is.c b/drivers/media/platform/exynos4-is/fimc-is.c index 1e40b555e..5a8d4f03a 100644 --- a/drivers/media/platform/exynos4-is/fimc-is.c +++ b/drivers/media/platform/exynos4-is/fimc-is.c @@ -631,6 +631,12 @@ static int fimc_is_hw_open_sensor(struct fimc_is *is, fimc_is_mem_barrier(); + /* + * Some user space use cases hang up here without this + * empirically chosen delay. + */ + udelay(100); + mcuctl_write(HIC_OPEN_SENSOR, is, MCUCTL_REG_ISSR(0)); mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1)); mcuctl_write(sensor->drvdata->id, is, MCUCTL_REG_ISSR(2)); diff --git a/drivers/media/platform/exynos4-is/fimc-isp-video.c b/drivers/media/platform/exynos4-is/fimc-isp-video.c index 6e6648446..c0816728c 100644 --- a/drivers/media/platform/exynos4-is/fimc-isp-video.c +++ b/drivers/media/platform/exynos4-is/fimc-isp-video.c @@ -30,7 +30,7 @@ #include <media/v4l2-ioctl.h> #include <media/videobuf2-v4l2.h> #include <media/videobuf2-dma-contig.h> -#include <media/exynos-fimc.h> +#include <media/drv-intf/exynos-fimc.h> #include "common.h" #include "media-dev.h" @@ -39,39 +39,36 @@ #include "fimc-is-param.h" static int isp_video_capture_queue_setup(struct vb2_queue *vq, - const void *parg, unsigned int *num_buffers, unsigned int *num_planes, unsigned int sizes[], void *allocators[]) { - const struct v4l2_format *pfmt = parg; struct fimc_isp *isp = vb2_get_drv_priv(vq); struct v4l2_pix_format_mplane *vid_fmt = &isp->video_capture.pixfmt; - const struct v4l2_pix_format_mplane *pixm = NULL; - const struct fimc_fmt *fmt; + const struct fimc_fmt *fmt = isp->video_capture.format; unsigned int wh, i; - if (pfmt) { - pixm = &pfmt->fmt.pix_mp; - fmt = fimc_isp_find_format(&pixm->pixelformat, NULL, -1); - wh = pixm->width * pixm->height; - } else { - fmt = isp->video_capture.format; - wh = vid_fmt->width * vid_fmt->height; - } + wh = vid_fmt->width * vid_fmt->height; if (fmt == NULL) return -EINVAL; *num_buffers = clamp_t(u32, *num_buffers, FIMC_ISP_REQ_BUFS_MIN, FIMC_ISP_REQ_BUFS_MAX); + if (*num_planes) { + if (*num_planes != fmt->memplanes) + return -EINVAL; + for (i = 0; i < *num_planes; i++) { + if (sizes[i] < (wh * fmt->depth[i]) / 8) + return -EINVAL; + allocators[i] = isp->alloc_ctx; + } + return 0; + } + *num_planes = fmt->memplanes; for (i = 0; i < fmt->memplanes; i++) { - unsigned int size = (wh * fmt->depth[i]) / 8; - if (pixm) - sizes[i] = max(size, pixm->plane_fmt[i].sizeimage); - else - sizes[i] = size; + sizes[i] = (wh * fmt->depth[i]) / 8; allocators[i] = isp->alloc_ctx; } @@ -221,8 +218,8 @@ static void isp_video_capture_buffer_queue(struct vb2_buffer *vb) ivb->dma_addr[i]; isp_dbg(2, &video->ve.vdev, - "dma_buf %pad (%d/%d/%d) addr: %pad\n", - &buf_index, ivb->index, i, vb->index, + "dma_buf %d (%d/%d/%d) addr: %pad\n", + buf_index, ivb->index, i, vb->index, &ivb->dma_addr[i]); } @@ -254,7 +251,7 @@ void fimc_isp_video_irq_handler(struct fimc_is *is) buf_index = (is->i2h_cmd.args[1] - 1) % video->buf_count; vbuf = &video->buffers[buf_index]->vb; - v4l2_get_timestamp(&vbuf->timestamp); + vbuf->vb2_buf.timestamp = ktime_get_ns(); vb2_buffer_done(&vbuf->vb2_buf, VB2_BUF_STATE_DONE); video->buf_mask &= ~BIT(buf_index); @@ -290,7 +287,7 @@ static int isp_video_open(struct file *file) goto rel_fh; if (v4l2_fh_is_singular_file(file)) { - mutex_lock(&me->parent->graph_mutex); + mutex_lock(&me->graph_obj.mdev->graph_mutex); ret = fimc_pipeline_call(ve, open, me, true); @@ -298,7 +295,7 @@ static int isp_video_open(struct file *file) if (ret == 0) me->use_count++; - mutex_unlock(&me->parent->graph_mutex); + mutex_unlock(&me->graph_obj.mdev->graph_mutex); } if (!ret) goto unlock; @@ -314,7 +311,7 @@ static int isp_video_release(struct file *file) struct fimc_isp *isp = video_drvdata(file); struct fimc_is_video *ivc = &isp->video_capture; struct media_entity *entity = &ivc->ve.vdev.entity; - struct media_device *mdev = entity->parent; + struct media_device *mdev = entity->graph_obj.mdev; mutex_lock(&isp->video_lock); @@ -469,8 +466,7 @@ static int isp_video_pipeline_validate(struct fimc_isp *isp) /* Retrieve format at the source pad */ pad = media_entity_remote_pad(pad); - if (pad == NULL || - media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) + if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) break; sd = media_entity_to_v4l2_subdev(pad->entity); @@ -620,7 +616,7 @@ int fimc_isp_video_device_register(struct fimc_isp *isp, vdev->lock = &isp->video_lock; iv->pad.flags = MEDIA_PAD_FL_SINK; - ret = media_entity_init(&vdev->entity, 1, &iv->pad, 0); + ret = media_entity_pads_init(&vdev->entity, 1, &iv->pad); if (ret < 0) return ret; diff --git a/drivers/media/platform/exynos4-is/fimc-isp.c b/drivers/media/platform/exynos4-is/fimc-isp.c index 5d78f5716..293b80702 100644 --- a/drivers/media/platform/exynos4-is/fimc-isp.c +++ b/drivers/media/platform/exynos4-is/fimc-isp.c @@ -708,8 +708,8 @@ int fimc_isp_subdev_create(struct fimc_isp *isp) isp->subdev_pads[FIMC_ISP_SD_PAD_SINK].flags = MEDIA_PAD_FL_SINK; isp->subdev_pads[FIMC_ISP_SD_PAD_SRC_FIFO].flags = MEDIA_PAD_FL_SOURCE; isp->subdev_pads[FIMC_ISP_SD_PAD_SRC_DMA].flags = MEDIA_PAD_FL_SOURCE; - ret = media_entity_init(&sd->entity, FIMC_ISP_SD_PADS_NUM, - isp->subdev_pads, 0); + ret = media_entity_pads_init(&sd->entity, FIMC_ISP_SD_PADS_NUM, + isp->subdev_pads); if (ret) return ret; diff --git a/drivers/media/platform/exynos4-is/fimc-isp.h b/drivers/media/platform/exynos4-is/fimc-isp.h index c2d25df85..e0686b5f1 100644 --- a/drivers/media/platform/exynos4-is/fimc-isp.h +++ b/drivers/media/platform/exynos4-is/fimc-isp.h @@ -24,7 +24,7 @@ #include <media/videobuf2-v4l2.h> #include <media/v4l2-device.h> #include <media/v4l2-mediabus.h> -#include <media/exynos-fimc.h> +#include <media/drv-intf/exynos-fimc.h> extern int fimc_isp_debug; diff --git a/drivers/media/platform/exynos4-is/fimc-lite-reg.c b/drivers/media/platform/exynos4-is/fimc-lite-reg.c index 0477716a2..f0acc550d 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite-reg.c +++ b/drivers/media/platform/exynos4-is/fimc-lite-reg.c @@ -12,7 +12,7 @@ #include <linux/bitops.h> #include <linux/delay.h> #include <linux/io.h> -#include <media/exynos-fimc.h> +#include <media/drv-intf/exynos-fimc.h> #include "fimc-lite-reg.h" #include "fimc-lite.h" diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c index 60660c3a5..e85649147 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.c +++ b/drivers/media/platform/exynos4-is/fimc-lite.c @@ -30,7 +30,7 @@ #include <media/v4l2-mem2mem.h> #include <media/videobuf2-v4l2.h> #include <media/videobuf2-dma-contig.h> -#include <media/exynos-fimc.h> +#include <media/drv-intf/exynos-fimc.h> #include "common.h" #include "fimc-core.h" @@ -292,7 +292,7 @@ static irqreturn_t flite_irq_handler(int irq, void *priv) test_bit(ST_FLITE_RUN, &fimc->state) && !list_empty(&fimc->active_buf_q)) { vbuf = fimc_lite_active_queue_pop(fimc); - v4l2_get_timestamp(&vbuf->vb.timestamp); + vbuf->vb.vb2_buf.timestamp = ktime_get_ns(); vbuf->vb.sequence = fimc->frame_count++; flite_hw_mask_dma_buffer(fimc, vbuf->index); vb2_buffer_done(&vbuf->vb.vb2_buf, VB2_BUF_STATE_DONE); @@ -355,37 +355,34 @@ static void stop_streaming(struct vb2_queue *q) fimc_lite_stop_capture(fimc, false); } -static int queue_setup(struct vb2_queue *vq, const void *parg, +static int queue_setup(struct vb2_queue *vq, unsigned int *num_buffers, unsigned int *num_planes, unsigned int sizes[], void *allocators[]) { - const struct v4l2_format *pfmt = parg; - const struct v4l2_pix_format_mplane *pixm = NULL; struct fimc_lite *fimc = vq->drv_priv; struct flite_frame *frame = &fimc->out_frame; const struct fimc_fmt *fmt = frame->fmt; - unsigned long wh; + unsigned long wh = frame->f_width * frame->f_height; int i; - if (pfmt) { - pixm = &pfmt->fmt.pix_mp; - fmt = fimc_lite_find_format(&pixm->pixelformat, NULL, 0, -1); - wh = pixm->width * pixm->height; - } else { - wh = frame->f_width * frame->f_height; - } - if (fmt == NULL) return -EINVAL; + if (*num_planes) { + if (*num_planes != fmt->memplanes) + return -EINVAL; + for (i = 0; i < *num_planes; i++) { + if (sizes[i] < (wh * fmt->depth[i]) / 8) + return -EINVAL; + allocators[i] = fimc->alloc_ctx; + } + return 0; + } + *num_planes = fmt->memplanes; for (i = 0; i < fmt->memplanes; i++) { - unsigned int size = (wh * fmt->depth[i]) / 8; - if (pixm) - sizes[i] = max(size, pixm->plane_fmt[i].sizeimage); - else - sizes[i] = size; + sizes[i] = (wh * fmt->depth[i]) / 8; allocators[i] = fimc->alloc_ctx; } @@ -497,7 +494,7 @@ static int fimc_lite_open(struct file *file) atomic_read(&fimc->out_path) != FIMC_IO_DMA) goto unlock; - mutex_lock(&me->parent->graph_mutex); + mutex_lock(&me->graph_obj.mdev->graph_mutex); ret = fimc_pipeline_call(&fimc->ve, open, me, true); @@ -505,7 +502,7 @@ static int fimc_lite_open(struct file *file) if (ret == 0) me->use_count++; - mutex_unlock(&me->parent->graph_mutex); + mutex_unlock(&me->graph_obj.mdev->graph_mutex); if (!ret) { fimc_lite_clear_event_counters(fimc); @@ -538,9 +535,9 @@ static int fimc_lite_release(struct file *file) fimc_pipeline_call(&fimc->ve, close); clear_bit(ST_FLITE_IN_USE, &fimc->state); - mutex_lock(&entity->parent->graph_mutex); + mutex_lock(&entity->graph_obj.mdev->graph_mutex); entity->use_count--; - mutex_unlock(&entity->parent->graph_mutex); + mutex_unlock(&entity->graph_obj.mdev->graph_mutex); } _vb2_fop_release(file, NULL); @@ -811,8 +808,7 @@ static int fimc_pipeline_validate(struct fimc_lite *fimc) } /* Retrieve format at the source pad */ pad = media_entity_remote_pad(pad); - if (pad == NULL || - media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) + if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) break; sd = media_entity_to_v4l2_subdev(pad->entity); @@ -985,7 +981,6 @@ static int fimc_lite_link_setup(struct media_entity *entity, { struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); struct fimc_lite *fimc = v4l2_get_subdevdata(sd); - unsigned int remote_ent_type = media_entity_type(remote->entity); int ret = 0; if (WARN_ON(fimc == NULL)) @@ -997,7 +992,7 @@ static int fimc_lite_link_setup(struct media_entity *entity, switch (local->index) { case FLITE_SD_PAD_SINK: - if (remote_ent_type != MEDIA_ENT_T_V4L2_SUBDEV) { + if (!is_media_entity_v4l2_subdev(remote->entity)) { ret = -EINVAL; break; } @@ -1015,7 +1010,7 @@ static int fimc_lite_link_setup(struct media_entity *entity, case FLITE_SD_PAD_SOURCE_DMA: if (!(flags & MEDIA_LNK_FL_ENABLED)) atomic_set(&fimc->out_path, FIMC_IO_NONE); - else if (remote_ent_type == MEDIA_ENT_T_DEVNODE) + else if (is_media_entity_v4l2_io(remote->entity)) atomic_set(&fimc->out_path, FIMC_IO_DMA); else ret = -EINVAL; @@ -1024,7 +1019,7 @@ static int fimc_lite_link_setup(struct media_entity *entity, case FLITE_SD_PAD_SOURCE_ISP: if (!(flags & MEDIA_LNK_FL_ENABLED)) atomic_set(&fimc->out_path, FIMC_IO_NONE); - else if (remote_ent_type == MEDIA_ENT_T_V4L2_SUBDEV) + else if (is_media_entity_v4l2_subdev(remote->entity)) atomic_set(&fimc->out_path, FIMC_IO_ISP); else ret = -EINVAL; @@ -1319,7 +1314,7 @@ static int fimc_lite_subdev_registered(struct v4l2_subdev *sd) return ret; fimc->vd_pad.flags = MEDIA_PAD_FL_SINK; - ret = media_entity_init(&vfd->entity, 1, &fimc->vd_pad, 0); + ret = media_entity_pads_init(&vfd->entity, 1, &fimc->vd_pad); if (ret < 0) return ret; @@ -1433,8 +1428,8 @@ static int fimc_lite_create_capture_subdev(struct fimc_lite *fimc) fimc->subdev_pads[FLITE_SD_PAD_SINK].flags = MEDIA_PAD_FL_SINK; fimc->subdev_pads[FLITE_SD_PAD_SOURCE_DMA].flags = MEDIA_PAD_FL_SOURCE; fimc->subdev_pads[FLITE_SD_PAD_SOURCE_ISP].flags = MEDIA_PAD_FL_SOURCE; - ret = media_entity_init(&sd->entity, FLITE_SD_PADS_NUM, - fimc->subdev_pads, 0); + ret = media_entity_pads_init(&sd->entity, FLITE_SD_PADS_NUM, + fimc->subdev_pads); if (ret) return ret; diff --git a/drivers/media/platform/exynos4-is/fimc-lite.h b/drivers/media/platform/exynos4-is/fimc-lite.h index b302305de..11690d563 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.h +++ b/drivers/media/platform/exynos4-is/fimc-lite.h @@ -23,7 +23,7 @@ #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-mediabus.h> -#include <media/exynos-fimc.h> +#include <media/drv-intf/exynos-fimc.h> #define FIMC_LITE_DRV_NAME "exynos-fimc-lite" #define FLITE_CLK_NAME "flite" diff --git a/drivers/media/platform/exynos4-is/fimc-m2m.c b/drivers/media/platform/exynos4-is/fimc-m2m.c index 4d1d64a46..55ec4c99d 100644 --- a/drivers/media/platform/exynos4-is/fimc-m2m.c +++ b/drivers/media/platform/exynos4-is/fimc-m2m.c @@ -132,7 +132,7 @@ static void fimc_device_run(void *priv) if (ret) goto dma_unlock; - dst_vb->timestamp = src_vb->timestamp; + dst_vb->vb2_buf.timestamp = src_vb->vb2_buf.timestamp; dst_vb->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; dst_vb->flags |= src_vb->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK; @@ -176,7 +176,7 @@ static void fimc_job_abort(void *priv) fimc_m2m_shutdown(priv); } -static int fimc_queue_setup(struct vb2_queue *vq, const void *parg, +static int fimc_queue_setup(struct vb2_queue *vq, unsigned int *num_buffers, unsigned int *num_planes, unsigned int sizes[], void *allocators[]) { @@ -739,7 +739,7 @@ int fimc_register_m2m_device(struct fimc_dev *fimc, return PTR_ERR(fimc->m2m.m2m_dev); } - ret = media_entity_init(&vfd->entity, 0, NULL, 0); + ret = media_entity_pads_init(&vfd->entity, 0, NULL); if (ret) goto err_me; diff --git a/drivers/media/platform/exynos4-is/fimc-reg.c b/drivers/media/platform/exynos4-is/fimc-reg.c index df0cbcb69..080672455 100644 --- a/drivers/media/platform/exynos4-is/fimc-reg.c +++ b/drivers/media/platform/exynos4-is/fimc-reg.c @@ -13,7 +13,7 @@ #include <linux/io.h> #include <linux/regmap.h> -#include <media/exynos-fimc.h> +#include <media/drv-intf/exynos-fimc.h> #include "media-dev.h" #include "fimc-reg.h" diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c index 4f5586a4c..e79ddbb1e 100644 --- a/drivers/media/platform/exynos4-is/media-dev.c +++ b/drivers/media/platform/exynos4-is/media-dev.c @@ -31,7 +31,7 @@ #include <media/v4l2-ctrls.h> #include <media/v4l2-of.h> #include <media/media-device.h> -#include <media/exynos-fimc.h> +#include <media/drv-intf/exynos-fimc.h> #include "media-dev.h" #include "fimc-core.h" @@ -88,8 +88,7 @@ static void fimc_pipeline_prepare(struct fimc_pipeline *p, break; } - if (pad == NULL || - media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) + if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) break; sd = media_entity_to_v4l2_subdev(pad->entity); @@ -187,6 +186,37 @@ error: } /** + * __fimc_pipeline_enable - enable power of all pipeline subdevs + * and the sensor clock + * @ep: video pipeline structure + * @fmd: fimc media device + * + * Called with the graph mutex held. + */ +static int __fimc_pipeline_enable(struct exynos_media_pipeline *ep, + struct fimc_md *fmd) +{ + struct fimc_pipeline *p = to_fimc_pipeline(ep); + int ret; + + /* Enable PXLASYNC clock if this pipeline includes FIMC-IS */ + if (!IS_ERR(fmd->wbclk[CLK_IDX_WB_B]) && p->subdevs[IDX_IS_ISP]) { + ret = clk_prepare_enable(fmd->wbclk[CLK_IDX_WB_B]); + if (ret < 0) + return ret; + } + + ret = fimc_pipeline_s_power(p, 1); + if (!ret) + return 0; + + if (!IS_ERR(fmd->wbclk[CLK_IDX_WB_B]) && p->subdevs[IDX_IS_ISP]) + clk_disable_unprepare(fmd->wbclk[CLK_IDX_WB_B]); + + return ret; +} + +/** * __fimc_pipeline_open - update the pipeline information, enable power * of all pipeline subdevs and the sensor clock * @me: media entity to start graph walk with @@ -200,7 +230,6 @@ static int __fimc_pipeline_open(struct exynos_media_pipeline *ep, struct fimc_md *fmd = entity_to_fimc_mdev(me); struct fimc_pipeline *p = to_fimc_pipeline(ep); struct v4l2_subdev *sd; - int ret; if (WARN_ON(p == NULL || me == NULL)) return -EINVAL; @@ -209,24 +238,16 @@ static int __fimc_pipeline_open(struct exynos_media_pipeline *ep, fimc_pipeline_prepare(p, me); sd = p->subdevs[IDX_SENSOR]; - if (sd == NULL) - return -EINVAL; - - /* Disable PXLASYNC clock if this pipeline includes FIMC-IS */ - if (!IS_ERR(fmd->wbclk[CLK_IDX_WB_B]) && p->subdevs[IDX_IS_ISP]) { - ret = clk_prepare_enable(fmd->wbclk[CLK_IDX_WB_B]); - if (ret < 0) - return ret; - } - - ret = fimc_pipeline_s_power(p, 1); - if (!ret) + if (sd == NULL) { + pr_warn("%s(): No sensor subdev\n", __func__); + /* + * Pipeline open cannot fail so as to make it possible + * for the user space to configure the pipeline. + */ return 0; + } - if (!IS_ERR(fmd->wbclk[CLK_IDX_WB_B]) && p->subdevs[IDX_IS_ISP]) - clk_disable_unprepare(fmd->wbclk[CLK_IDX_WB_B]); - - return ret; + return __fimc_pipeline_enable(ep, fmd); } /** @@ -270,10 +291,43 @@ static int __fimc_pipeline_s_stream(struct exynos_media_pipeline *ep, bool on) { IDX_CSIS, IDX_FLITE, IDX_FIMC, IDX_SENSOR, IDX_IS_ISP }, }; struct fimc_pipeline *p = to_fimc_pipeline(ep); + struct fimc_md *fmd = entity_to_fimc_mdev(&p->subdevs[IDX_CSIS]->entity); + enum fimc_subdev_index sd_id; int i, ret = 0; - if (p->subdevs[IDX_SENSOR] == NULL) - return -ENODEV; + if (p->subdevs[IDX_SENSOR] == NULL) { + if (!fmd->user_subdev_api) { + /* + * Sensor must be already discovered if we + * aren't in the user_subdev_api mode + */ + return -ENODEV; + } + + /* Get pipeline sink entity */ + if (p->subdevs[IDX_FIMC]) + sd_id = IDX_FIMC; + else if (p->subdevs[IDX_IS_ISP]) + sd_id = IDX_IS_ISP; + else if (p->subdevs[IDX_FLITE]) + sd_id = IDX_FLITE; + else + return -ENODEV; + + /* + * Sensor could have been linked between open and STREAMON - + * check if this is the case. + */ + fimc_pipeline_prepare(p, &p->subdevs[sd_id]->entity); + + if (p->subdevs[IDX_SENSOR] == NULL) + return -ENODEV; + + ret = __fimc_pipeline_enable(ep, fmd); + if (ret < 0) + return ret; + + } for (i = 0; i < IDX_MAX; i++) { unsigned int idx = seq[on][i]; @@ -283,8 +337,10 @@ static int __fimc_pipeline_s_stream(struct exynos_media_pipeline *ep, bool on) if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) goto error; } + return 0; error: + fimc_pipeline_s_power(p, !on); for (; i >= 0; i--) { unsigned int idx = seq[on][i]; v4l2_subdev_call(p->subdevs[idx], video, s_stream, !on); @@ -729,7 +785,7 @@ static int __fimc_md_create_fimc_sink_links(struct fimc_md *fmd, flags = ((1 << i) & link_mask) ? MEDIA_LNK_FL_ENABLED : 0; sink = &fmd->fimc[i]->vid_cap.subdev.entity; - ret = media_entity_create_link(source, pad, sink, + ret = media_create_pad_link(source, pad, sink, FIMC_SD_PAD_SINK_CAM, flags); if (ret) return ret; @@ -749,7 +805,7 @@ static int __fimc_md_create_fimc_sink_links(struct fimc_md *fmd, continue; sink = &fmd->fimc_lite[i]->subdev.entity; - ret = media_entity_create_link(source, pad, sink, + ret = media_create_pad_link(source, pad, sink, FLITE_SD_PAD_SINK, 0); if (ret) return ret; @@ -781,13 +837,13 @@ static int __fimc_md_create_flite_source_links(struct fimc_md *fmd) source = &fimc->subdev.entity; sink = &fimc->ve.vdev.entity; /* FIMC-LITE's subdev and video node */ - ret = media_entity_create_link(source, FLITE_SD_PAD_SOURCE_DMA, + ret = media_create_pad_link(source, FLITE_SD_PAD_SOURCE_DMA, sink, 0, 0); if (ret) break; /* Link from FIMC-LITE to IS-ISP subdev */ sink = &fmd->fimc_is->isp.subdev.entity; - ret = media_entity_create_link(source, FLITE_SD_PAD_SOURCE_ISP, + ret = media_create_pad_link(source, FLITE_SD_PAD_SOURCE_ISP, sink, 0, 0); if (ret) break; @@ -811,7 +867,7 @@ static int __fimc_md_create_fimc_is_links(struct fimc_md *fmd) /* Link from FIMC-IS-ISP subdev to FIMC */ sink = &fmd->fimc[i]->vid_cap.subdev.entity; - ret = media_entity_create_link(source, FIMC_ISP_SD_PAD_SRC_FIFO, + ret = media_create_pad_link(source, FIMC_ISP_SD_PAD_SRC_FIFO, sink, FIMC_SD_PAD_SINK_FIFO, 0); if (ret) return ret; @@ -824,7 +880,7 @@ static int __fimc_md_create_fimc_is_links(struct fimc_md *fmd) if (sink->num_pads == 0) return 0; - return media_entity_create_link(source, FIMC_ISP_SD_PAD_SRC_DMA, + return media_create_pad_link(source, FIMC_ISP_SD_PAD_SRC_DMA, sink, 0, 0); } @@ -873,7 +929,7 @@ static int fimc_md_create_links(struct fimc_md *fmd) return -EINVAL; pad = sensor->entity.num_pads - 1; - ret = media_entity_create_link(&sensor->entity, pad, + ret = media_create_pad_link(&sensor->entity, pad, &csis->entity, CSIS_PAD_SINK, MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); @@ -927,7 +983,7 @@ static int fimc_md_create_links(struct fimc_md *fmd) source = &fmd->fimc[i]->vid_cap.subdev.entity; sink = &fmd->fimc[i]->vid_cap.ve.vdev.entity; - ret = media_entity_create_link(source, FIMC_SD_PAD_SOURCE, + ret = media_create_pad_link(source, FIMC_SD_PAD_SOURCE, sink, 0, flags); if (ret) break; @@ -1046,11 +1102,11 @@ static int __fimc_md_modify_pipeline(struct media_entity *entity, bool enable) return ret; } -/* Locking: called with entity->parent->graph_mutex mutex held. */ -static int __fimc_md_modify_pipelines(struct media_entity *entity, bool enable) +/* Locking: called with entity->graph_obj.mdev->graph_mutex mutex held. */ +static int __fimc_md_modify_pipelines(struct media_entity *entity, bool enable, + struct media_entity_graph *graph) { struct media_entity *entity_err = entity; - struct media_entity_graph graph; int ret; /* @@ -1059,10 +1115,10 @@ static int __fimc_md_modify_pipelines(struct media_entity *entity, bool enable) * through active links. This is needed as we cannot power on/off the * subdevs in random order. */ - media_entity_graph_walk_start(&graph, entity); + media_entity_graph_walk_start(graph, entity); - while ((entity = media_entity_graph_walk_next(&graph))) { - if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE) + while ((entity = media_entity_graph_walk_next(graph))) { + if (!is_media_entity_v4l2_io(entity)) continue; ret = __fimc_md_modify_pipeline(entity, enable); @@ -1072,11 +1128,12 @@ static int __fimc_md_modify_pipelines(struct media_entity *entity, bool enable) } return 0; - err: - media_entity_graph_walk_start(&graph, entity_err); - while ((entity_err = media_entity_graph_walk_next(&graph))) { - if (media_entity_type(entity_err) != MEDIA_ENT_T_DEVNODE) +err: + media_entity_graph_walk_start(graph, entity_err); + + while ((entity_err = media_entity_graph_walk_next(graph))) { + if (!is_media_entity_v4l2_io(entity_err)) continue; __fimc_md_modify_pipeline(entity_err, !enable); @@ -1091,21 +1148,29 @@ static int __fimc_md_modify_pipelines(struct media_entity *entity, bool enable) static int fimc_md_link_notify(struct media_link *link, unsigned int flags, unsigned int notification) { + struct media_entity_graph *graph = + &container_of(link->graph_obj.mdev, struct fimc_md, + media_dev)->link_setup_graph; struct media_entity *sink = link->sink->entity; int ret = 0; /* Before link disconnection */ if (notification == MEDIA_DEV_NOTIFY_PRE_LINK_CH) { + ret = media_entity_graph_walk_init(graph, + link->graph_obj.mdev); + if (ret) + return ret; if (!(flags & MEDIA_LNK_FL_ENABLED)) - ret = __fimc_md_modify_pipelines(sink, false); + ret = __fimc_md_modify_pipelines(sink, false, graph); #if 0 else /* TODO: Link state change validation */ #endif /* After link activation */ - } else if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH && - (link->flags & MEDIA_LNK_FL_ENABLED)) { - ret = __fimc_md_modify_pipelines(sink, true); + } else if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH) { + if (link->flags & MEDIA_LNK_FL_ENABLED) + ret = __fimc_md_modify_pipelines(sink, true, graph); + media_entity_graph_walk_cleanup(graph); } return ret ? -EPIPE : 0; @@ -1314,7 +1379,10 @@ static int subdev_notifier_complete(struct v4l2_async_notifier *notifier) ret = v4l2_device_register_subdev_nodes(&fmd->v4l2_dev); unlock: mutex_unlock(&fmd->media_dev.graph_mutex); - return ret; + if (ret < 0) + return ret; + + return media_device_register(&fmd->media_dev); } static int fimc_md_probe(struct platform_device *pdev) @@ -1345,18 +1413,14 @@ static int fimc_md_probe(struct platform_device *pdev) fmd->use_isp = fimc_md_is_isp_available(dev->of_node); fmd->user_subdev_api = true; + media_device_init(&fmd->media_dev); + ret = v4l2_device_register(dev, &fmd->v4l2_dev); if (ret < 0) { v4l2_err(v4l2_dev, "Failed to register v4l2_device: %d\n", ret); return ret; } - ret = media_device_register(&fmd->media_dev); - if (ret < 0) { - v4l2_err(v4l2_dev, "Failed to register media device: %d\n", ret); - goto err_v4l2_dev; - } - ret = fimc_md_get_clocks(fmd); if (ret) goto err_md; @@ -1425,8 +1489,7 @@ err_clk: err_m_ent: fimc_md_unregister_entities(fmd); err_md: - media_device_unregister(&fmd->media_dev); -err_v4l2_dev: + media_device_cleanup(&fmd->media_dev); v4l2_device_unregister(&fmd->v4l2_dev); return ret; } @@ -1446,6 +1509,7 @@ static int fimc_md_remove(struct platform_device *pdev) fimc_md_unregister_entities(fmd); fimc_md_pipelines_free(fmd); media_device_unregister(&fmd->media_dev); + media_device_cleanup(&fmd->media_dev); fimc_md_put_clocks(fmd); return 0; diff --git a/drivers/media/platform/exynos4-is/media-dev.h b/drivers/media/platform/exynos4-is/media-dev.h index 03214541f..ed122cb2d 100644 --- a/drivers/media/platform/exynos4-is/media-dev.h +++ b/drivers/media/platform/exynos4-is/media-dev.h @@ -19,7 +19,7 @@ #include <media/media-entity.h> #include <media/v4l2-device.h> #include <media/v4l2-subdev.h> -#include <media/exynos-fimc.h> +#include <media/drv-intf/exynos-fimc.h> #include "fimc-core.h" #include "fimc-lite.h" @@ -154,6 +154,7 @@ struct fimc_md { bool user_subdev_api; spinlock_t slock; struct list_head pipelines; + struct media_entity_graph link_setup_graph; }; static inline @@ -164,8 +165,8 @@ struct fimc_sensor_info *source_to_sensor_info(struct fimc_source_info *si) static inline struct fimc_md *entity_to_fimc_mdev(struct media_entity *me) { - return me->parent == NULL ? NULL : - container_of(me->parent, struct fimc_md, media_dev); + return me->graph_obj.mdev == NULL ? NULL : + container_of(me->graph_obj.mdev, struct fimc_md, media_dev); } static inline struct fimc_md *notifier_to_fimc_md(struct v4l2_async_notifier *n) @@ -175,12 +176,12 @@ static inline struct fimc_md *notifier_to_fimc_md(struct v4l2_async_notifier *n) static inline void fimc_md_graph_lock(struct exynos_video_entity *ve) { - mutex_lock(&ve->vdev.entity.parent->graph_mutex); + mutex_lock(&ve->vdev.entity.graph_obj.mdev->graph_mutex); } static inline void fimc_md_graph_unlock(struct exynos_video_entity *ve) { - mutex_unlock(&ve->vdev.entity.parent->graph_mutex); + mutex_unlock(&ve->vdev.entity.graph_obj.mdev->graph_mutex); } int fimc_md_set_camclk(struct v4l2_subdev *sd, bool on); diff --git a/drivers/media/platform/exynos4-is/mipi-csis.c b/drivers/media/platform/exynos4-is/mipi-csis.c index 4b85105dc..ac5e50e59 100644 --- a/drivers/media/platform/exynos4-is/mipi-csis.c +++ b/drivers/media/platform/exynos4-is/mipi-csis.c @@ -29,7 +29,7 @@ #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/videodev2.h> -#include <media/exynos-fimc.h> +#include <media/drv-intf/exynos-fimc.h> #include <media/v4l2-of.h> #include <media/v4l2-subdev.h> @@ -866,8 +866,8 @@ static int s5pcsis_probe(struct platform_device *pdev) state->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK; state->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; - ret = media_entity_init(&state->sd.entity, - CSIS_PADS_NUM, state->pads, 0); + ret = media_entity_pads_init(&state->sd.entity, + CSIS_PADS_NUM, state->pads); if (ret < 0) goto e_clkdis; diff --git a/drivers/media/platform/m2m-deinterlace.c b/drivers/media/platform/m2m-deinterlace.c index 29973f9bf..7383818c2 100644 --- a/drivers/media/platform/m2m-deinterlace.c +++ b/drivers/media/platform/m2m-deinterlace.c @@ -207,7 +207,7 @@ static void dma_callback(void *data) src_vb = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx); dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx); - dst_vb->timestamp = src_vb->timestamp; + dst_vb->vb2_buf.timestamp = src_vb->vb2_buf.timestamp; dst_vb->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; dst_vb->flags |= src_vb->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK; @@ -798,7 +798,6 @@ struct vb2_dc_conf { }; static int deinterlace_queue_setup(struct vb2_queue *vq, - const void *parg, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) { diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c index aa2b44041..9b878deb1 100644 --- a/drivers/media/platform/marvell-ccic/mcam-core.c +++ b/drivers/media/platform/marvell-ccic/mcam-core.c @@ -25,7 +25,7 @@ #include <media/v4l2-ioctl.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-event.h> -#include <media/ov7670.h> +#include <media/i2c/ov7670.h> #include <media/videobuf2-vmalloc.h> #include <media/videobuf2-dma-contig.h> #include <media/videobuf2-dma-sg.h> @@ -226,7 +226,7 @@ static void mcam_buffer_done(struct mcam_camera *cam, int frame, vbuf->vb2_buf.planes[0].bytesused = cam->pix_format.sizeimage; vbuf->sequence = cam->buf_seq[frame]; vbuf->field = V4L2_FIELD_NONE; - v4l2_get_timestamp(&vbuf->timestamp); + vbuf->vb2_buf.timestamp = ktime_get_ns(); vb2_set_plane_payload(&vbuf->vb2_buf, 0, cam->pix_format.sizeimage); vb2_buffer_done(&vbuf->vb2_buf, VB2_BUF_STATE_DONE); } @@ -1049,24 +1049,25 @@ static int mcam_read_setup(struct mcam_camera *cam) */ static int mcam_vb_queue_setup(struct vb2_queue *vq, - const void *parg, unsigned int *nbufs, + unsigned int *nbufs, unsigned int *num_planes, unsigned int sizes[], void *alloc_ctxs[]) { - const struct v4l2_format *fmt = parg; struct mcam_camera *cam = vb2_get_drv_priv(vq); int minbufs = (cam->buffer_mode == B_DMA_contig) ? 3 : 2; + unsigned size = cam->pix_format.sizeimage; - if (fmt && fmt->fmt.pix.sizeimage < cam->pix_format.sizeimage) - return -EINVAL; - sizes[0] = fmt ? fmt->fmt.pix.sizeimage : cam->pix_format.sizeimage; - *num_planes = 1; /* Someday we have to support planar formats... */ if (*nbufs < minbufs) *nbufs = minbufs; if (cam->buffer_mode == B_DMA_contig) alloc_ctxs[0] = cam->vb_alloc_ctx; else if (cam->buffer_mode == B_DMA_sg) alloc_ctxs[0] = cam->vb_alloc_ctx_sg; + + if (*num_planes) + return sizes[0] < size ? -EINVAL : 0; + sizes[0] = size; + *num_planes = 1; /* Someday we have to support planar formats... */ return 0; } diff --git a/drivers/media/platform/marvell-ccic/mmp-driver.c b/drivers/media/platform/marvell-ccic/mmp-driver.c index b5f165a68..816f4b6a7 100644 --- a/drivers/media/platform/marvell-ccic/mmp-driver.c +++ b/drivers/media/platform/marvell-ccic/mmp-driver.c @@ -18,7 +18,7 @@ #include <linux/slab.h> #include <linux/videodev2.h> #include <media/v4l2-device.h> -#include <media/mmp-camera.h> +#include <linux/platform_data/media/mmp-camera.h> #include <linux/device.h> #include <linux/platform_device.h> #include <linux/gpio.h> diff --git a/drivers/media/platform/mx2_emmaprp.c b/drivers/media/platform/mx2_emmaprp.c index 03a1b6066..3c4012d42 100644 --- a/drivers/media/platform/mx2_emmaprp.c +++ b/drivers/media/platform/mx2_emmaprp.c @@ -375,7 +375,7 @@ static irqreturn_t emmaprp_irq(int irq_emma, void *data) src_vb = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx); dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx); - dst_vb->timestamp = src_vb->timestamp; + dst_vb->vb2_buf.timestamp = src_vb->vb2_buf.timestamp; dst_vb->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; dst_vb->flags |= @@ -689,7 +689,6 @@ static const struct v4l2_ioctl_ops emmaprp_ioctl_ops = { * Queue operations */ static int emmaprp_queue_setup(struct vb2_queue *vq, - const void *parg, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) { diff --git a/drivers/media/platform/omap/Kconfig b/drivers/media/platform/omap/Kconfig index 217d613b0..e8e2db181 100644 --- a/drivers/media/platform/omap/Kconfig +++ b/drivers/media/platform/omap/Kconfig @@ -5,9 +5,9 @@ config VIDEO_OMAP2_VOUT tristate "OMAP2/OMAP3 V4L2-Display driver" depends on MMU depends on ARCH_OMAP2 || ARCH_OMAP3 + depends on FB_OMAP2 select VIDEOBUF_GEN select VIDEOBUF_DMA_CONTIG - select OMAP2_DSS if HAS_IOMEM && ARCH_OMAP2PLUS select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3 select VIDEO_OMAP2_VOUT_VRFB if VIDEO_OMAP2_VOUT && OMAP2_VRFB select FRAME_VECTOR diff --git a/drivers/media/platform/omap/omap_vout_vrfb.c b/drivers/media/platform/omap/omap_vout_vrfb.c index c6e252760..b8638e4e1 100644 --- a/drivers/media/platform/omap/omap_vout_vrfb.c +++ b/drivers/media/platform/omap/omap_vout_vrfb.c @@ -79,10 +79,12 @@ void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout) int j; for (j = 0; j < VRFB_NUM_BUFS; j++) { - omap_vout_free_buffer(vout->smsshado_virt_addr[j], - vout->smsshado_size); - vout->smsshado_virt_addr[j] = 0; - vout->smsshado_phy_addr[j] = 0; + if (vout->smsshado_virt_addr[j]) { + omap_vout_free_buffer(vout->smsshado_virt_addr[j], + vout->smsshado_size); + vout->smsshado_virt_addr[j] = 0; + vout->smsshado_phy_addr[j] = 0; + } } } diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index 56e683b19..0bcfa553c 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -683,15 +683,15 @@ static irqreturn_t isp_isr(int irq, void *_isp) * * Return the total number of users of all video device nodes in the pipeline. */ -static int isp_pipeline_pm_use_count(struct media_entity *entity) +static int isp_pipeline_pm_use_count(struct media_entity *entity, + struct media_entity_graph *graph) { - struct media_entity_graph graph; int use = 0; - media_entity_graph_walk_start(&graph, entity); + media_entity_graph_walk_start(graph, entity); - while ((entity = media_entity_graph_walk_next(&graph))) { - if (media_entity_type(entity) == MEDIA_ENT_T_DEVNODE) + while ((entity = media_entity_graph_walk_next(graph))) { + if (is_media_entity_v4l2_io(entity)) use += entity->use_count; } @@ -714,7 +714,7 @@ static int isp_pipeline_pm_power_one(struct media_entity *entity, int change) struct v4l2_subdev *subdev; int ret; - subdev = media_entity_type(entity) == MEDIA_ENT_T_V4L2_SUBDEV + subdev = is_media_entity_v4l2_subdev(entity) ? media_entity_to_v4l2_subdev(entity) : NULL; if (entity->use_count == 0 && change > 0 && subdev != NULL) { @@ -742,29 +742,29 @@ static int isp_pipeline_pm_power_one(struct media_entity *entity, int change) * * Return 0 on success or a negative error code on failure. */ -static int isp_pipeline_pm_power(struct media_entity *entity, int change) +static int isp_pipeline_pm_power(struct media_entity *entity, int change, + struct media_entity_graph *graph) { - struct media_entity_graph graph; struct media_entity *first = entity; int ret = 0; if (!change) return 0; - media_entity_graph_walk_start(&graph, entity); + media_entity_graph_walk_start(graph, entity); - while (!ret && (entity = media_entity_graph_walk_next(&graph))) - if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE) + while (!ret && (entity = media_entity_graph_walk_next(graph))) + if (is_media_entity_v4l2_subdev(entity)) ret = isp_pipeline_pm_power_one(entity, change); if (!ret) - return 0; + return ret; - media_entity_graph_walk_start(&graph, first); + media_entity_graph_walk_start(graph, first); - while ((first = media_entity_graph_walk_next(&graph)) + while ((first = media_entity_graph_walk_next(graph)) && first != entity) - if (media_entity_type(first) != MEDIA_ENT_T_DEVNODE) + if (is_media_entity_v4l2_subdev(first)) isp_pipeline_pm_power_one(first, -change); return ret; @@ -782,23 +782,24 @@ static int isp_pipeline_pm_power(struct media_entity *entity, int change) * off is assumed to never fail. No failure can occur when the use parameter is * set to 0. */ -int omap3isp_pipeline_pm_use(struct media_entity *entity, int use) +int omap3isp_pipeline_pm_use(struct media_entity *entity, int use, + struct media_entity_graph *graph) { int change = use ? 1 : -1; int ret; - mutex_lock(&entity->parent->graph_mutex); + mutex_lock(&entity->graph_obj.mdev->graph_mutex); /* Apply use count to node. */ entity->use_count += change; WARN_ON(entity->use_count < 0); /* Apply power change to connected non-nodes. */ - ret = isp_pipeline_pm_power(entity, change); + ret = isp_pipeline_pm_power(entity, change, graph); if (ret < 0) entity->use_count -= change; - mutex_unlock(&entity->parent->graph_mutex); + mutex_unlock(&entity->graph_obj.mdev->graph_mutex); return ret; } @@ -820,35 +821,49 @@ int omap3isp_pipeline_pm_use(struct media_entity *entity, int use) static int isp_pipeline_link_notify(struct media_link *link, u32 flags, unsigned int notification) { + struct media_entity_graph *graph = + &container_of(link->graph_obj.mdev, struct isp_device, + media_dev)->pm_count_graph; struct media_entity *source = link->source->entity; struct media_entity *sink = link->sink->entity; - int source_use = isp_pipeline_pm_use_count(source); - int sink_use = isp_pipeline_pm_use_count(sink); - int ret; + int source_use; + int sink_use; + int ret = 0; + + if (notification == MEDIA_DEV_NOTIFY_PRE_LINK_CH) { + ret = media_entity_graph_walk_init(graph, + link->graph_obj.mdev); + if (ret) + return ret; + } + + source_use = isp_pipeline_pm_use_count(source, graph); + sink_use = isp_pipeline_pm_use_count(sink, graph); if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH && !(flags & MEDIA_LNK_FL_ENABLED)) { /* Powering off entities is assumed to never fail. */ - isp_pipeline_pm_power(source, -sink_use); - isp_pipeline_pm_power(sink, -source_use); + isp_pipeline_pm_power(source, -sink_use, graph); + isp_pipeline_pm_power(sink, -source_use, graph); return 0; } if (notification == MEDIA_DEV_NOTIFY_PRE_LINK_CH && (flags & MEDIA_LNK_FL_ENABLED)) { - ret = isp_pipeline_pm_power(source, sink_use); + ret = isp_pipeline_pm_power(source, sink_use, graph); if (ret < 0) return ret; - ret = isp_pipeline_pm_power(sink, source_use); + ret = isp_pipeline_pm_power(sink, source_use, graph); if (ret < 0) - isp_pipeline_pm_power(source, -sink_use); - - return ret; + isp_pipeline_pm_power(source, -sink_use, graph); } - return 0; + if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH) + media_entity_graph_walk_cleanup(graph); + + return ret; } /* ----------------------------------------------------------------------------- @@ -881,7 +896,7 @@ static int isp_pipeline_enable(struct isp_pipeline *pipe, * starting entities if the pipeline won't start anyway (those entities * would then likely fail to stop, making the problem worse). */ - if (pipe->entities & isp->crashed) + if (media_entity_enum_intersects(&pipe->ent_enum, &isp->crashed)) return -EIO; spin_lock_irqsave(&pipe->lock, flags); @@ -897,8 +912,7 @@ static int isp_pipeline_enable(struct isp_pipeline *pipe, break; pad = media_entity_remote_pad(pad); - if (pad == NULL || - media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) + if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) break; entity = pad->entity; @@ -987,8 +1001,7 @@ static int isp_pipeline_disable(struct isp_pipeline *pipe) break; pad = media_entity_remote_pad(pad); - if (pad == NULL || - media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) + if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) break; entity = pad->entity; @@ -1028,7 +1041,8 @@ static int isp_pipeline_disable(struct isp_pipeline *pipe) dev_info(isp->dev, "Unable to stop %s\n", subdev->name); isp->stop_failure = true; if (subdev == &isp->isp_prev.subdev) - isp->crashed |= 1U << subdev->entity.id; + media_entity_enum_set(&isp->crashed, + &subdev->entity); failure = -ETIMEDOUT; } } @@ -1234,7 +1248,7 @@ static int isp_reset(struct isp_device *isp) } isp->stop_failure = false; - isp->crashed = 0; + media_entity_enum_zero(&isp->crashed); return 0; } @@ -1645,7 +1659,8 @@ static void __omap3isp_put(struct isp_device *isp, bool save_ctx) /* Reset the ISP if an entity has failed to stop. This is the * only way to recover from such conditions. */ - if (isp->crashed || isp->stop_failure) + if (!media_entity_enum_empty(&isp->crashed) || + isp->stop_failure) isp_reset(isp); isp_disable_clocks(isp); } @@ -1792,6 +1807,7 @@ static void isp_unregister_entities(struct isp_device *isp) v4l2_device_unregister(&isp->v4l2_dev); media_device_unregister(&isp->media_dev); + media_device_cleanup(&isp->media_dev); } static int isp_link_entity( @@ -1862,7 +1878,7 @@ static int isp_link_entity( return -EINVAL; } - return media_entity_create_link(entity, i, input, pad, flags); + return media_create_pad_link(entity, i, input, pad, flags); } static int isp_register_entities(struct isp_device *isp) @@ -1874,12 +1890,7 @@ static int isp_register_entities(struct isp_device *isp) sizeof(isp->media_dev.model)); isp->media_dev.hw_revision = isp->revision; isp->media_dev.link_notify = isp_pipeline_link_notify; - ret = media_device_register(&isp->media_dev); - if (ret < 0) { - dev_err(isp->dev, "%s: Media device registration failed (%d)\n", - __func__, ret); - return ret; - } + media_device_init(&isp->media_dev); isp->v4l2_dev.mdev = &isp->media_dev; ret = v4l2_device_register(isp->dev, &isp->v4l2_dev); @@ -1930,6 +1941,118 @@ done: return ret; } +/* + * isp_create_links() - Create links for internal and external ISP entities + * @isp : Pointer to ISP device + * + * This function creates all links between ISP internal and external entities. + * + * Return: A negative error code on failure or zero on success. Possible error + * codes are those returned by media_create_pad_link(). + */ +static int isp_create_links(struct isp_device *isp) +{ + int ret; + + /* Create links between entities and video nodes. */ + ret = media_create_pad_link( + &isp->isp_csi2a.subdev.entity, CSI2_PAD_SOURCE, + &isp->isp_csi2a.video_out.video.entity, 0, 0); + if (ret < 0) + return ret; + + ret = media_create_pad_link( + &isp->isp_ccp2.video_in.video.entity, 0, + &isp->isp_ccp2.subdev.entity, CCP2_PAD_SINK, 0); + if (ret < 0) + return ret; + + ret = media_create_pad_link( + &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_OF, + &isp->isp_ccdc.video_out.video.entity, 0, 0); + if (ret < 0) + return ret; + + ret = media_create_pad_link( + &isp->isp_prev.video_in.video.entity, 0, + &isp->isp_prev.subdev.entity, PREV_PAD_SINK, 0); + if (ret < 0) + return ret; + + ret = media_create_pad_link( + &isp->isp_prev.subdev.entity, PREV_PAD_SOURCE, + &isp->isp_prev.video_out.video.entity, 0, 0); + if (ret < 0) + return ret; + + ret = media_create_pad_link( + &isp->isp_res.video_in.video.entity, 0, + &isp->isp_res.subdev.entity, RESZ_PAD_SINK, 0); + if (ret < 0) + return ret; + + ret = media_create_pad_link( + &isp->isp_res.subdev.entity, RESZ_PAD_SOURCE, + &isp->isp_res.video_out.video.entity, 0, 0); + + if (ret < 0) + return ret; + + /* Create links between entities. */ + ret = media_create_pad_link( + &isp->isp_csi2a.subdev.entity, CSI2_PAD_SOURCE, + &isp->isp_ccdc.subdev.entity, CCDC_PAD_SINK, 0); + if (ret < 0) + return ret; + + ret = media_create_pad_link( + &isp->isp_ccp2.subdev.entity, CCP2_PAD_SOURCE, + &isp->isp_ccdc.subdev.entity, CCDC_PAD_SINK, 0); + if (ret < 0) + return ret; + + ret = media_create_pad_link( + &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP, + &isp->isp_prev.subdev.entity, PREV_PAD_SINK, 0); + if (ret < 0) + return ret; + + ret = media_create_pad_link( + &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_OF, + &isp->isp_res.subdev.entity, RESZ_PAD_SINK, 0); + if (ret < 0) + return ret; + + ret = media_create_pad_link( + &isp->isp_prev.subdev.entity, PREV_PAD_SOURCE, + &isp->isp_res.subdev.entity, RESZ_PAD_SINK, 0); + if (ret < 0) + return ret; + + ret = media_create_pad_link( + &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP, + &isp->isp_aewb.subdev.entity, 0, + MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE); + if (ret < 0) + return ret; + + ret = media_create_pad_link( + &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP, + &isp->isp_af.subdev.entity, 0, + MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE); + if (ret < 0) + return ret; + + ret = media_create_pad_link( + &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP, + &isp->isp_hist.subdev.entity, 0, + MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE); + if (ret < 0) + return ret; + + return 0; +} + static void isp_cleanup_modules(struct isp_device *isp) { omap3isp_h3a_aewb_cleanup(isp); @@ -2000,62 +2123,8 @@ static int isp_initialize_modules(struct isp_device *isp) goto error_h3a_af; } - /* Connect the submodules. */ - ret = media_entity_create_link( - &isp->isp_csi2a.subdev.entity, CSI2_PAD_SOURCE, - &isp->isp_ccdc.subdev.entity, CCDC_PAD_SINK, 0); - if (ret < 0) - goto error_link; - - ret = media_entity_create_link( - &isp->isp_ccp2.subdev.entity, CCP2_PAD_SOURCE, - &isp->isp_ccdc.subdev.entity, CCDC_PAD_SINK, 0); - if (ret < 0) - goto error_link; - - ret = media_entity_create_link( - &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP, - &isp->isp_prev.subdev.entity, PREV_PAD_SINK, 0); - if (ret < 0) - goto error_link; - - ret = media_entity_create_link( - &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_OF, - &isp->isp_res.subdev.entity, RESZ_PAD_SINK, 0); - if (ret < 0) - goto error_link; - - ret = media_entity_create_link( - &isp->isp_prev.subdev.entity, PREV_PAD_SOURCE, - &isp->isp_res.subdev.entity, RESZ_PAD_SINK, 0); - if (ret < 0) - goto error_link; - - ret = media_entity_create_link( - &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP, - &isp->isp_aewb.subdev.entity, 0, - MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE); - if (ret < 0) - goto error_link; - - ret = media_entity_create_link( - &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP, - &isp->isp_af.subdev.entity, 0, - MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE); - if (ret < 0) - goto error_link; - - ret = media_entity_create_link( - &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP, - &isp->isp_hist.subdev.entity, 0, - MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE); - if (ret < 0) - goto error_link; - return 0; -error_link: - omap3isp_h3a_af_cleanup(isp); error_h3a_af: omap3isp_h3a_aewb_cleanup(isp); error_h3a_aewb: @@ -2149,6 +2218,8 @@ static int isp_remove(struct platform_device *pdev) isp_detach_iommu(isp); __omap3isp_put(isp, false); + media_entity_enum_cleanup(&isp->crashed); + return 0; } @@ -2278,28 +2349,43 @@ static int isp_subdev_notifier_bound(struct v4l2_async_notifier *async, struct v4l2_subdev *subdev, struct v4l2_async_subdev *asd) { - struct isp_device *isp = container_of(async, struct isp_device, - notifier); struct isp_async_subdev *isd = container_of(asd, struct isp_async_subdev, asd); - int ret; - - ret = isp_link_entity(isp, &subdev->entity, isd->bus.interface); - if (ret < 0) - return ret; isd->sd = subdev; isd->sd->host_priv = &isd->bus; - return ret; + return 0; } static int isp_subdev_notifier_complete(struct v4l2_async_notifier *async) { struct isp_device *isp = container_of(async, struct isp_device, notifier); + struct v4l2_device *v4l2_dev = &isp->v4l2_dev; + struct v4l2_subdev *sd; + struct isp_bus_cfg *bus; + int ret; + + ret = media_entity_enum_init(&isp->crashed, &isp->media_dev); + if (ret) + return ret; - return v4l2_device_register_subdev_nodes(&isp->v4l2_dev); + list_for_each_entry(sd, &v4l2_dev->subdevs, list) { + /* Only try to link entities whose interface was set on bound */ + if (sd->host_priv) { + bus = (struct isp_bus_cfg *)sd->host_priv; + ret = isp_link_entity(isp, &sd->entity, bus->interface); + if (ret < 0) + return ret; + } + } + + ret = v4l2_device_register_subdev_nodes(&isp->v4l2_dev); + if (ret < 0) + return ret; + + return media_device_register(&isp->media_dev); } /* @@ -2465,6 +2551,10 @@ static int isp_probe(struct platform_device *pdev) if (ret < 0) goto error_modules; + ret = isp_create_links(isp); + if (ret < 0) + goto error_register_entities; + isp->notifier.bound = isp_subdev_notifier_bound; isp->notifier.complete = isp_subdev_notifier_complete; diff --git a/drivers/media/platform/omap3isp/isp.h b/drivers/media/platform/omap3isp/isp.h index 5acc2e651..49b7f71ac 100644 --- a/drivers/media/platform/omap3isp/isp.h +++ b/drivers/media/platform/omap3isp/isp.h @@ -17,6 +17,7 @@ #ifndef OMAP3_ISP_CORE_H #define OMAP3_ISP_CORE_H +#include <media/media-entity.h> #include <media/v4l2-async.h> #include <media/v4l2-device.h> #include <linux/clk-provider.h> @@ -152,7 +153,7 @@ struct isp_xclk { * @stat_lock: Spinlock for handling statistics * @isp_mutex: Mutex for serializing requests to ISP. * @stop_failure: Indicates that an entity failed to stop. - * @crashed: Bitmask of crashed entities (indexed by entity ID) + * @crashed: Crashed ent_enum * @has_context: Context has been saved at least once and can be restored. * @ref_count: Reference count for handling multiple ISP requests. * @cam_ick: Pointer to camera interface clock structure. @@ -176,6 +177,7 @@ struct isp_device { struct v4l2_device v4l2_dev; struct v4l2_async_notifier notifier; struct media_device media_dev; + struct media_entity_graph pm_count_graph; struct device *dev; u32 revision; @@ -194,7 +196,7 @@ struct isp_device { spinlock_t stat_lock; /* common lock for statistic drivers */ struct mutex isp_mutex; /* For handling ref_count field */ bool stop_failure; - u32 crashed; + struct media_entity_enum crashed; int has_context; int ref_count; unsigned int autoidle; @@ -265,7 +267,8 @@ void omap3isp_subclk_enable(struct isp_device *isp, void omap3isp_subclk_disable(struct isp_device *isp, enum isp_subclk_resource res); -int omap3isp_pipeline_pm_use(struct media_entity *entity, int use); +int omap3isp_pipeline_pm_use(struct media_entity *entity, int use, + struct media_entity_graph *graph); int omap3isp_register_entities(struct platform_device *pdev, struct v4l2_device *v4l2_dev); diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c index a6a61cce4..bb3974c98 100644 --- a/drivers/media/platform/omap3isp/ispccdc.c +++ b/drivers/media/platform/omap3isp/ispccdc.c @@ -1608,7 +1608,7 @@ static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc) /* Wait for the CCDC to become idle. */ if (ccdc_sbl_wait_idle(ccdc, 1000)) { dev_info(isp->dev, "CCDC won't become idle!\n"); - isp->crashed |= 1U << ccdc->subdev.entity.id; + media_entity_enum_set(&isp->crashed, &ccdc->subdev.entity); omap3isp_pipeline_cancel_stream(pipe); return 0; } @@ -2513,9 +2513,14 @@ static int ccdc_link_setup(struct media_entity *entity, struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd); struct isp_device *isp = to_isp_device(ccdc); + unsigned int index = local->index; - switch (local->index | media_entity_type(remote->entity)) { - case CCDC_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV: + /* FIXME: this is actually a hack! */ + if (is_media_entity_v4l2_subdev(remote->entity)) + index |= 2 << 16; + + switch (index) { + case CCDC_PAD_SINK | 2 << 16: /* Read from the sensor (parallel interface), CCP2, CSI2a or * CSI2c. */ @@ -2543,7 +2548,7 @@ static int ccdc_link_setup(struct media_entity *entity, * Revisit this when it will be implemented, and return -EBUSY for now. */ - case CCDC_PAD_SOURCE_VP | MEDIA_ENT_T_V4L2_SUBDEV: + case CCDC_PAD_SOURCE_VP | 2 << 16: /* Write to preview engine, histogram and H3A. When none of * those links are active, the video port can be disabled. */ @@ -2556,7 +2561,7 @@ static int ccdc_link_setup(struct media_entity *entity, } break; - case CCDC_PAD_SOURCE_OF | MEDIA_ENT_T_DEVNODE: + case CCDC_PAD_SOURCE_OF: /* Write to memory */ if (flags & MEDIA_LNK_FL_ENABLED) { if (ccdc->output & ~CCDC_OUTPUT_MEMORY) @@ -2567,7 +2572,7 @@ static int ccdc_link_setup(struct media_entity *entity, } break; - case CCDC_PAD_SOURCE_OF | MEDIA_ENT_T_V4L2_SUBDEV: + case CCDC_PAD_SOURCE_OF | 2 << 16: /* Write to resizer */ if (flags & MEDIA_LNK_FL_ENABLED) { if (ccdc->output & ~CCDC_OUTPUT_RESIZER) @@ -2650,7 +2655,7 @@ static int ccdc_init_entities(struct isp_ccdc_device *ccdc) pads[CCDC_PAD_SOURCE_OF].flags = MEDIA_PAD_FL_SOURCE; me->ops = &ccdc_media_ops; - ret = media_entity_init(me, CCDC_PADS_NUM, pads, 0); + ret = media_entity_pads_init(me, CCDC_PADS_NUM, pads); if (ret < 0) return ret; @@ -2664,19 +2669,11 @@ static int ccdc_init_entities(struct isp_ccdc_device *ccdc) ret = omap3isp_video_init(&ccdc->video_out, "CCDC"); if (ret < 0) - goto error_video; - - /* Connect the CCDC subdev to the video node. */ - ret = media_entity_create_link(&ccdc->subdev.entity, CCDC_PAD_SOURCE_OF, - &ccdc->video_out.video.entity, 0, 0); - if (ret < 0) - goto error_link; + goto error; return 0; -error_link: - omap3isp_video_cleanup(&ccdc->video_out); -error_video: +error: media_entity_cleanup(me); return ret; } diff --git a/drivers/media/platform/omap3isp/ispccp2.c b/drivers/media/platform/omap3isp/ispccp2.c index 38e6a974c..ca0952385 100644 --- a/drivers/media/platform/omap3isp/ispccp2.c +++ b/drivers/media/platform/omap3isp/ispccp2.c @@ -956,9 +956,14 @@ static int ccp2_link_setup(struct media_entity *entity, { struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd); + unsigned int index = local->index; - switch (local->index | media_entity_type(remote->entity)) { - case CCP2_PAD_SINK | MEDIA_ENT_T_DEVNODE: + /* FIXME: this is actually a hack! */ + if (is_media_entity_v4l2_subdev(remote->entity)) + index |= 2 << 16; + + switch (index) { + case CCP2_PAD_SINK: /* read from memory */ if (flags & MEDIA_LNK_FL_ENABLED) { if (ccp2->input == CCP2_INPUT_SENSOR) @@ -970,7 +975,7 @@ static int ccp2_link_setup(struct media_entity *entity, } break; - case CCP2_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV: + case CCP2_PAD_SINK | 2 << 16: /* read from sensor/phy */ if (flags & MEDIA_LNK_FL_ENABLED) { if (ccp2->input == CCP2_INPUT_MEMORY) @@ -981,7 +986,7 @@ static int ccp2_link_setup(struct media_entity *entity, ccp2->input = CCP2_INPUT_NONE; } break; - case CCP2_PAD_SOURCE | MEDIA_ENT_T_V4L2_SUBDEV: + case CCP2_PAD_SOURCE | 2 << 16: /* write to video port/ccdc */ if (flags & MEDIA_LNK_FL_ENABLED) ccp2->output = CCP2_OUTPUT_CCDC; @@ -1071,7 +1076,7 @@ static int ccp2_init_entities(struct isp_ccp2_device *ccp2) pads[CCP2_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; me->ops = &ccp2_media_ops; - ret = media_entity_init(me, CCP2_PADS_NUM, pads, 0); + ret = media_entity_pads_init(me, CCP2_PADS_NUM, pads); if (ret < 0) return ret; @@ -1097,19 +1102,11 @@ static int ccp2_init_entities(struct isp_ccp2_device *ccp2) ret = omap3isp_video_init(&ccp2->video_in, "CCP2"); if (ret < 0) - goto error_video; - - /* Connect the video node to the ccp2 subdev. */ - ret = media_entity_create_link(&ccp2->video_in.video.entity, 0, - &ccp2->subdev.entity, CCP2_PAD_SINK, 0); - if (ret < 0) - goto error_link; + goto error; return 0; -error_link: - omap3isp_video_cleanup(&ccp2->video_in); -error_video: +error: media_entity_cleanup(&ccp2->subdev.entity); return ret; } diff --git a/drivers/media/platform/omap3isp/ispcsi2.c b/drivers/media/platform/omap3isp/ispcsi2.c index a78338d01..f75a1be29 100644 --- a/drivers/media/platform/omap3isp/ispcsi2.c +++ b/drivers/media/platform/omap3isp/ispcsi2.c @@ -1144,14 +1144,19 @@ static int csi2_link_setup(struct media_entity *entity, struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd); struct isp_csi2_ctrl_cfg *ctrl = &csi2->ctrl; + unsigned int index = local->index; /* * The ISP core doesn't support pipelines with multiple video outputs. * Revisit this when it will be implemented, and return -EBUSY for now. */ - switch (local->index | media_entity_type(remote->entity)) { - case CSI2_PAD_SOURCE | MEDIA_ENT_T_DEVNODE: + /* FIXME: this is actually a hack! */ + if (is_media_entity_v4l2_subdev(remote->entity)) + index |= 2 << 16; + + switch (index) { + case CSI2_PAD_SOURCE: if (flags & MEDIA_LNK_FL_ENABLED) { if (csi2->output & ~CSI2_OUTPUT_MEMORY) return -EBUSY; @@ -1161,7 +1166,7 @@ static int csi2_link_setup(struct media_entity *entity, } break; - case CSI2_PAD_SOURCE | MEDIA_ENT_T_V4L2_SUBDEV: + case CSI2_PAD_SOURCE | 2 << 16: if (flags & MEDIA_LNK_FL_ENABLED) { if (csi2->output & ~CSI2_OUTPUT_CCDC) return -EBUSY; @@ -1245,7 +1250,7 @@ static int csi2_init_entities(struct isp_csi2_device *csi2) | MEDIA_PAD_FL_MUST_CONNECT; me->ops = &csi2_media_ops; - ret = media_entity_init(me, CSI2_PADS_NUM, pads, 0); + ret = media_entity_pads_init(me, CSI2_PADS_NUM, pads); if (ret < 0) return ret; @@ -1264,16 +1269,8 @@ static int csi2_init_entities(struct isp_csi2_device *csi2) if (ret < 0) goto error_video; - /* Connect the CSI2 subdev to the video node. */ - ret = media_entity_create_link(&csi2->subdev.entity, CSI2_PAD_SOURCE, - &csi2->video_out.video.entity, 0, 0); - if (ret < 0) - goto error_link; - return 0; -error_link: - omap3isp_video_cleanup(&csi2->video_out); error_video: media_entity_cleanup(&csi2->subdev.entity); return ret; diff --git a/drivers/media/platform/omap3isp/isppreview.c b/drivers/media/platform/omap3isp/isppreview.c index 13803270d..84a96670e 100644 --- a/drivers/media/platform/omap3isp/isppreview.c +++ b/drivers/media/platform/omap3isp/isppreview.c @@ -2144,9 +2144,14 @@ static int preview_link_setup(struct media_entity *entity, { struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); struct isp_prev_device *prev = v4l2_get_subdevdata(sd); + unsigned int index = local->index; - switch (local->index | media_entity_type(remote->entity)) { - case PREV_PAD_SINK | MEDIA_ENT_T_DEVNODE: + /* FIXME: this is actually a hack! */ + if (is_media_entity_v4l2_subdev(remote->entity)) + index |= 2 << 16; + + switch (index) { + case PREV_PAD_SINK: /* read from memory */ if (flags & MEDIA_LNK_FL_ENABLED) { if (prev->input == PREVIEW_INPUT_CCDC) @@ -2158,7 +2163,7 @@ static int preview_link_setup(struct media_entity *entity, } break; - case PREV_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV: + case PREV_PAD_SINK | 2 << 16: /* read from ccdc */ if (flags & MEDIA_LNK_FL_ENABLED) { if (prev->input == PREVIEW_INPUT_MEMORY) @@ -2175,7 +2180,7 @@ static int preview_link_setup(struct media_entity *entity, * Revisit this when it will be implemented, and return -EBUSY for now. */ - case PREV_PAD_SOURCE | MEDIA_ENT_T_DEVNODE: + case PREV_PAD_SOURCE: /* write to memory */ if (flags & MEDIA_LNK_FL_ENABLED) { if (prev->output & ~PREVIEW_OUTPUT_MEMORY) @@ -2186,7 +2191,7 @@ static int preview_link_setup(struct media_entity *entity, } break; - case PREV_PAD_SOURCE | MEDIA_ENT_T_V4L2_SUBDEV: + case PREV_PAD_SOURCE | 2 << 16: /* write to resizer */ if (flags & MEDIA_LNK_FL_ENABLED) { if (prev->output & ~PREVIEW_OUTPUT_RESIZER) @@ -2282,7 +2287,7 @@ static int preview_init_entities(struct isp_prev_device *prev) pads[PREV_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; me->ops = &preview_media_ops; - ret = media_entity_init(me, PREV_PADS_NUM, pads, 0); + ret = media_entity_pads_init(me, PREV_PADS_NUM, pads); if (ret < 0) return ret; @@ -2311,21 +2316,8 @@ static int preview_init_entities(struct isp_prev_device *prev) if (ret < 0) goto error_video_out; - /* Connect the video nodes to the previewer subdev. */ - ret = media_entity_create_link(&prev->video_in.video.entity, 0, - &prev->subdev.entity, PREV_PAD_SINK, 0); - if (ret < 0) - goto error_link; - - ret = media_entity_create_link(&prev->subdev.entity, PREV_PAD_SOURCE, - &prev->video_out.video.entity, 0, 0); - if (ret < 0) - goto error_link; - return 0; -error_link: - omap3isp_video_cleanup(&prev->video_out); error_video_out: omap3isp_video_cleanup(&prev->video_in); error_video_in: diff --git a/drivers/media/platform/omap3isp/ispresizer.c b/drivers/media/platform/omap3isp/ispresizer.c index 7cfb43dc0..0b6a87508 100644 --- a/drivers/media/platform/omap3isp/ispresizer.c +++ b/drivers/media/platform/omap3isp/ispresizer.c @@ -1623,9 +1623,14 @@ static int resizer_link_setup(struct media_entity *entity, { struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); struct isp_res_device *res = v4l2_get_subdevdata(sd); + unsigned int index = local->index; - switch (local->index | media_entity_type(remote->entity)) { - case RESZ_PAD_SINK | MEDIA_ENT_T_DEVNODE: + /* FIXME: this is actually a hack! */ + if (is_media_entity_v4l2_subdev(remote->entity)) + index |= 2 << 16; + + switch (index) { + case RESZ_PAD_SINK: /* read from memory */ if (flags & MEDIA_LNK_FL_ENABLED) { if (res->input == RESIZER_INPUT_VP) @@ -1637,7 +1642,7 @@ static int resizer_link_setup(struct media_entity *entity, } break; - case RESZ_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV: + case RESZ_PAD_SINK | 2 << 16: /* read from ccdc or previewer */ if (flags & MEDIA_LNK_FL_ENABLED) { if (res->input == RESIZER_INPUT_MEMORY) @@ -1649,7 +1654,7 @@ static int resizer_link_setup(struct media_entity *entity, } break; - case RESZ_PAD_SOURCE | MEDIA_ENT_T_DEVNODE: + case RESZ_PAD_SOURCE: /* resizer always write to memory */ break; @@ -1728,7 +1733,7 @@ static int resizer_init_entities(struct isp_res_device *res) pads[RESZ_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; me->ops = &resizer_media_ops; - ret = media_entity_init(me, RESZ_PADS_NUM, pads, 0); + ret = media_entity_pads_init(me, RESZ_PADS_NUM, pads); if (ret < 0) return ret; @@ -1755,21 +1760,8 @@ static int resizer_init_entities(struct isp_res_device *res) res->video_out.video.entity.flags |= MEDIA_ENT_FL_DEFAULT; - /* Connect the video nodes to the resizer subdev. */ - ret = media_entity_create_link(&res->video_in.video.entity, 0, - &res->subdev.entity, RESZ_PAD_SINK, 0); - if (ret < 0) - goto error_link; - - ret = media_entity_create_link(&res->subdev.entity, RESZ_PAD_SOURCE, - &res->video_out.video.entity, 0, 0); - if (ret < 0) - goto error_link; - return 0; -error_link: - omap3isp_video_cleanup(&res->video_out); error_video_out: omap3isp_video_cleanup(&res->video_in); error_video_in: diff --git a/drivers/media/platform/omap3isp/ispstat.c b/drivers/media/platform/omap3isp/ispstat.c index 94d4c295d..1b9217d3b 100644 --- a/drivers/media/platform/omap3isp/ispstat.c +++ b/drivers/media/platform/omap3isp/ispstat.c @@ -1028,7 +1028,7 @@ static int isp_stat_init_entities(struct ispstat *stat, const char *name, stat->pad.flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT; me->ops = NULL; - return media_entity_init(me, 1, &stat->pad, 0); + return media_entity_pads_init(me, 1, &stat->pad); } int omap3isp_stat_init(struct ispstat *stat, const char *name, diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c index f4f591652..994dfc081 100644 --- a/drivers/media/platform/omap3isp/ispvideo.c +++ b/drivers/media/platform/omap3isp/ispvideo.c @@ -210,8 +210,7 @@ isp_video_remote_subdev(struct isp_video *video, u32 *pad) remote = media_entity_remote_pad(&video->pad); - if (remote == NULL || - media_entity_type(remote->entity) != MEDIA_ENT_T_V4L2_SUBDEV) + if (!remote || !is_media_entity_v4l2_subdev(remote->entity)) return NULL; if (pad) @@ -226,16 +225,23 @@ static int isp_video_get_graph_data(struct isp_video *video, { struct media_entity_graph graph; struct media_entity *entity = &video->video.entity; - struct media_device *mdev = entity->parent; + struct media_device *mdev = entity->graph_obj.mdev; struct isp_video *far_end = NULL; + int ret; mutex_lock(&mdev->graph_mutex); + ret = media_entity_graph_walk_init(&graph, entity->graph_obj.mdev); + if (ret) { + mutex_unlock(&mdev->graph_mutex); + return ret; + } + media_entity_graph_walk_start(&graph, entity); while ((entity = media_entity_graph_walk_next(&graph))) { struct isp_video *__video; - pipe->entities |= 1 << entity->id; + media_entity_enum_set(&pipe->ent_enum, entity); if (far_end != NULL) continue; @@ -243,7 +249,7 @@ static int isp_video_get_graph_data(struct isp_video *video, if (entity == &video->video.entity) continue; - if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE) + if (!is_media_entity_v4l2_io(entity)) continue; __video = to_isp_video(media_entity_to_video_device(entity)); @@ -253,6 +259,8 @@ static int isp_video_get_graph_data(struct isp_video *video, mutex_unlock(&mdev->graph_mutex); + media_entity_graph_walk_cleanup(&graph); + if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { pipe->input = far_end; pipe->output = video; @@ -320,7 +328,6 @@ isp_video_check_format(struct isp_video *video, struct isp_video_fh *vfh) */ static int isp_video_queue_setup(struct vb2_queue *queue, - const void *parg, unsigned int *count, unsigned int *num_planes, unsigned int sizes[], void *alloc_ctxs[]) { @@ -467,7 +474,7 @@ struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video) list_del(&buf->irqlist); spin_unlock_irqrestore(&video->irqlock, flags); - v4l2_get_timestamp(&buf->vb.timestamp); + buf->vb.vb2_buf.timestamp = ktime_get_ns(); /* Do frame number propagation only if this is the output video node. * Frame number either comes from the CSI receivers or it gets @@ -901,7 +908,7 @@ static int isp_video_check_external_subdevs(struct isp_video *video, for (i = 0; i < ARRAY_SIZE(ents); i++) { /* Is the entity part of the pipeline? */ - if (!(pipe->entities & (1 << ents[i]->id))) + if (!media_entity_enum_test(&pipe->ent_enum, ents[i])) continue; /* ISP entities have always sink pad == 0. Find source. */ @@ -919,7 +926,7 @@ static int isp_video_check_external_subdevs(struct isp_video *video, return -EINVAL; } - if (media_entity_type(source) != MEDIA_ENT_T_V4L2_SUBDEV) + if (!is_media_entity_v4l2_subdev(source)) return 0; pipe->external = media_entity_to_v4l2_subdev(source); @@ -953,7 +960,8 @@ static int isp_video_check_external_subdevs(struct isp_video *video, pipe->external_rate = ctrl.value64; - if (pipe->entities & (1 << isp->isp_ccdc.subdev.entity.id)) { + if (media_entity_enum_test(&pipe->ent_enum, + &isp->isp_ccdc.subdev.entity)) { unsigned int rate = UINT_MAX; /* * Check that maximum allowed CCDC pixel rate isn't @@ -1019,7 +1027,9 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) pipe = video->video.entity.pipe ? to_isp_pipeline(&video->video.entity) : &video->pipe; - pipe->entities = 0; + ret = media_entity_enum_init(&pipe->ent_enum, &video->isp->media_dev); + if (ret) + goto err_enum_init; /* TODO: Implement PM QoS */ pipe->l3_ick = clk_get_rate(video->isp->clock[ISP_CLK_L3_ICK]); @@ -1093,6 +1103,7 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) } mutex_unlock(&video->stream_lock); + return 0; err_set_stream: @@ -1113,7 +1124,11 @@ err_pipeline_start: INIT_LIST_HEAD(&video->dmaqueue); video->queue = NULL; + media_entity_enum_cleanup(&pipe->ent_enum); + +err_enum_init: mutex_unlock(&video->stream_lock); + return ret; } @@ -1165,6 +1180,8 @@ isp_video_streamoff(struct file *file, void *fh, enum v4l2_buf_type type) /* TODO: Implement PM QoS */ media_entity_pipeline_stop(&video->video.entity); + media_entity_enum_cleanup(&pipe->ent_enum); + done: mutex_unlock(&video->stream_lock); return 0; @@ -1244,7 +1261,12 @@ static int isp_video_open(struct file *file) goto done; } - ret = omap3isp_pipeline_pm_use(&video->video.entity, 1); + ret = media_entity_graph_walk_init(&handle->graph, + &video->isp->media_dev); + if (ret) + goto done; + + ret = omap3isp_pipeline_pm_use(&video->video.entity, 1, &handle->graph); if (ret < 0) { omap3isp_put(video->isp); goto done; @@ -1275,6 +1297,7 @@ static int isp_video_open(struct file *file) done: if (ret < 0) { v4l2_fh_del(&handle->vfh); + media_entity_graph_walk_cleanup(&handle->graph); kfree(handle); } @@ -1294,7 +1317,8 @@ static int isp_video_release(struct file *file) vb2_queue_release(&handle->queue); mutex_unlock(&video->queue_lock); - omap3isp_pipeline_pm_use(&video->video.entity, 0); + omap3isp_pipeline_pm_use(&video->video.entity, 0, &handle->graph); + media_entity_graph_walk_cleanup(&handle->graph); /* Release the file handle. */ v4l2_fh_del(vfh); @@ -1368,7 +1392,7 @@ int omap3isp_video_init(struct isp_video *video, const char *name) if (IS_ERR(video->alloc_ctx)) return PTR_ERR(video->alloc_ctx); - ret = media_entity_init(&video->video.entity, 1, &video->pad, 0); + ret = media_entity_pads_init(&video->video.entity, 1, &video->pad); if (ret < 0) { vb2_dma_contig_cleanup_ctx(video->alloc_ctx); return ret; diff --git a/drivers/media/platform/omap3isp/ispvideo.h b/drivers/media/platform/omap3isp/ispvideo.h index bcf0e0acc..156429878 100644 --- a/drivers/media/platform/omap3isp/ispvideo.h +++ b/drivers/media/platform/omap3isp/ispvideo.h @@ -80,7 +80,7 @@ enum isp_pipeline_state { * struct isp_pipeline - An ISP hardware pipeline * @field: The field being processed by the pipeline * @error: A hardware error occurred during capture - * @entities: Bitmask of entities in the pipeline (indexed by entity ID) + * @ent_enum: Entities in the pipeline */ struct isp_pipeline { struct media_pipeline pipe; @@ -89,7 +89,7 @@ struct isp_pipeline { enum isp_pipeline_stream_state stream_state; struct isp_video *input; struct isp_video *output; - u32 entities; + struct media_entity_enum ent_enum; unsigned long l3_ick; unsigned int max_rate; enum v4l2_field field; @@ -189,6 +189,7 @@ struct isp_video_fh { struct vb2_queue queue; struct v4l2_format format; struct v4l2_fract timeperframe; + struct media_entity_graph graph; }; #define to_isp_video_fh(fh) container_of(fh, struct isp_video_fh, vfh) diff --git a/drivers/media/platform/rcar_jpu.c b/drivers/media/platform/rcar_jpu.c index f8e3e83c5..485f5259a 100644 --- a/drivers/media/platform/rcar_jpu.c +++ b/drivers/media/platform/rcar_jpu.c @@ -1015,28 +1015,33 @@ error_free: * ============================================================================ */ static int jpu_queue_setup(struct vb2_queue *vq, - const void *parg, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) { - const struct v4l2_format *fmt = parg; struct jpu_ctx *ctx = vb2_get_drv_priv(vq); struct jpu_q_data *q_data; unsigned int i; q_data = jpu_get_q_data(ctx, vq->type); - *nplanes = q_data->format.num_planes; + if (*nplanes) { + if (*nplanes != q_data->format.num_planes) + return -EINVAL; - for (i = 0; i < *nplanes; i++) { - unsigned int q_size = q_data->format.plane_fmt[i].sizeimage; - unsigned int f_size = fmt ? - fmt->fmt.pix_mp.plane_fmt[i].sizeimage : 0; + for (i = 0; i < *nplanes; i++) { + unsigned int q_size = q_data->format.plane_fmt[i].sizeimage; - if (fmt && f_size < q_size) - return -EINVAL; + if (sizes[i] < q_size) + return -EINVAL; + alloc_ctxs[i] = ctx->jpu->alloc_ctx; + } + return 0; + } - sizes[i] = fmt ? f_size : q_size; + *nplanes = q_data->format.num_planes; + + for (i = 0; i < *nplanes; i++) { + sizes[i] = q_data->format.plane_fmt[i].sizeimage; alloc_ctxs[i] = ctx->jpu->alloc_ctx; } @@ -1300,17 +1305,17 @@ static int jpu_release(struct file *file) struct jpu *jpu = video_drvdata(file); struct jpu_ctx *ctx = fh_to_ctx(file->private_data); - mutex_lock(&jpu->mutex); - if (--jpu->ref_count == 0) - clk_disable_unprepare(jpu->clk); - mutex_unlock(&jpu->mutex); - v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); v4l2_ctrl_handler_free(&ctx->ctrl_handler); v4l2_fh_del(&ctx->fh); v4l2_fh_exit(&ctx->fh); kfree(ctx); + mutex_lock(&jpu->mutex); + if (--jpu->ref_count == 0) + clk_disable_unprepare(jpu->clk); + mutex_unlock(&jpu->mutex); + return 0; } @@ -1560,12 +1565,9 @@ static irqreturn_t jpu_irq_handler(int irq, void *dev_id) } dst_buf->field = src_buf->field; - dst_buf->timestamp = src_buf->timestamp; + dst_buf->vb2_buf.timestamp = src_buf->vb2_buf.timestamp; if (src_buf->flags & V4L2_BUF_FLAG_TIMECODE) dst_buf->timecode = src_buf->timecode; - dst_buf->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; - dst_buf->flags |= src_buf->flags & - V4L2_BUF_FLAG_TSTAMP_SRC_MASK; dst_buf->flags = src_buf->flags & (V4L2_BUF_FLAG_TIMECODE | V4L2_BUF_FLAG_KEYFRAME | V4L2_BUF_FLAG_PFRAME | V4L2_BUF_FLAG_BFRAME | diff --git a/drivers/media/platform/s3c-camif/camif-capture.c b/drivers/media/platform/s3c-camif/camif-capture.c index 537b858cb..bd060ef5d 100644 --- a/drivers/media/platform/s3c-camif/camif-capture.c +++ b/drivers/media/platform/s3c-camif/camif-capture.c @@ -338,7 +338,7 @@ irqreturn_t s3c_camif_irq_handler(int irq, void *priv) if (!WARN_ON(vbuf == NULL)) { /* Dequeue a filled buffer */ - v4l2_get_timestamp(&vbuf->vb.timestamp); + vbuf->vb.vb2_buf.timestamp = ktime_get_ns(); vbuf->vb.sequence = vp->frame_sequence++; vb2_buffer_done(&vbuf->vb.vb2_buf, VB2_BUF_STATE_DONE); @@ -435,39 +435,28 @@ static void stop_streaming(struct vb2_queue *vq) camif_stop_capture(vp); } -static int queue_setup(struct vb2_queue *vq, const void *parg, +static int queue_setup(struct vb2_queue *vq, unsigned int *num_buffers, unsigned int *num_planes, unsigned int sizes[], void *allocators[]) { - const struct v4l2_format *pfmt = parg; - const struct v4l2_pix_format *pix = NULL; struct camif_vp *vp = vb2_get_drv_priv(vq); struct camif_dev *camif = vp->camif; struct camif_frame *frame = &vp->out_frame; - const struct camif_fmt *fmt; + const struct camif_fmt *fmt = vp->out_fmt; unsigned int size; - if (pfmt) { - pix = &pfmt->fmt.pix; - fmt = s3c_camif_find_format(vp, &pix->pixelformat, -1); - if (fmt == NULL) - return -EINVAL; - size = (pix->width * pix->height * fmt->depth) / 8; - } else { - fmt = vp->out_fmt; - if (fmt == NULL) - return -EINVAL; - size = (frame->f_width * frame->f_height * fmt->depth) / 8; - } - - *num_planes = 1; + if (fmt == NULL) + return -EINVAL; - if (pix) - sizes[0] = max(size, pix->sizeimage); - else - sizes[0] = size; + size = (frame->f_width * frame->f_height * fmt->depth) / 8; allocators[0] = camif->alloc_ctx; + if (*num_planes) + return sizes[0] < size ? -EINVAL : 0; + + *num_planes = 1; + sizes[0] = size; + pr_debug("size: %u\n", sizes[0]); return 0; } @@ -833,7 +822,7 @@ static int camif_pipeline_validate(struct camif_dev *camif) /* Retrieve format at the sensor subdev source pad */ pad = media_entity_remote_pad(&camif->pads[0]); - if (!pad || media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) + if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) return -EPIPE; src_fmt.pad = pad->index; @@ -1155,7 +1144,7 @@ int s3c_camif_register_video_node(struct camif_dev *camif, int idx) goto err_vd_rel; vp->pad.flags = MEDIA_PAD_FL_SINK; - ret = media_entity_init(&vfd->entity, 1, &vp->pad, 0); + ret = media_entity_pads_init(&vfd->entity, 1, &vp->pad); if (ret) goto err_vd_rel; @@ -1570,8 +1559,8 @@ int s3c_camif_create_subdev(struct camif_dev *camif) camif->pads[CAMIF_SD_PAD_SOURCE_C].flags = MEDIA_PAD_FL_SOURCE; camif->pads[CAMIF_SD_PAD_SOURCE_P].flags = MEDIA_PAD_FL_SOURCE; - ret = media_entity_init(&sd->entity, CAMIF_SD_PADS_NUM, - camif->pads, 0); + ret = media_entity_pads_init(&sd->entity, CAMIF_SD_PADS_NUM, + camif->pads); if (ret) return ret; diff --git a/drivers/media/platform/s3c-camif/camif-core.c b/drivers/media/platform/s3c-camif/camif-core.c index 1ba9bb08f..0b44b9acc 100644 --- a/drivers/media/platform/s3c-camif/camif-core.c +++ b/drivers/media/platform/s3c-camif/camif-core.c @@ -263,7 +263,7 @@ static int camif_create_media_links(struct camif_dev *camif) { int i, ret; - ret = media_entity_create_link(&camif->sensor.sd->entity, 0, + ret = media_create_pad_link(&camif->sensor.sd->entity, 0, &camif->subdev.entity, CAMIF_SD_PAD_SINK, MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); @@ -271,7 +271,7 @@ static int camif_create_media_links(struct camif_dev *camif) return ret; for (i = 1; i < CAMIF_SD_PADS_NUM && !ret; i++) { - ret = media_entity_create_link(&camif->subdev.entity, i, + ret = media_create_pad_link(&camif->subdev.entity, i, &camif->vp[i - 1].vdev.entity, 0, MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); @@ -305,7 +305,7 @@ static void camif_unregister_media_entities(struct camif_dev *camif) /* * Media device */ -static int camif_media_dev_register(struct camif_dev *camif) +static int camif_media_dev_init(struct camif_dev *camif) { struct media_device *md = &camif->media_dev; struct v4l2_device *v4l2_dev = &camif->v4l2_dev; @@ -324,14 +324,12 @@ static int camif_media_dev_register(struct camif_dev *camif) strlcpy(v4l2_dev->name, "s3c-camif", sizeof(v4l2_dev->name)); v4l2_dev->mdev = md; + media_device_init(md); + ret = v4l2_device_register(camif->dev, v4l2_dev); if (ret < 0) return ret; - ret = media_device_register(md); - if (ret < 0) - v4l2_device_unregister(v4l2_dev); - return ret; } @@ -483,7 +481,7 @@ static int s3c_camif_probe(struct platform_device *pdev) goto err_alloc; } - ret = camif_media_dev_register(camif); + ret = camif_media_dev_init(camif); if (ret < 0) goto err_mdev; @@ -510,6 +508,11 @@ static int s3c_camif_probe(struct platform_device *pdev) goto err_unlock; mutex_unlock(&camif->media_dev.graph_mutex); + + ret = media_device_register(&camif->media_dev); + if (ret < 0) + goto err_sens; + pm_runtime_put(dev); return 0; @@ -518,6 +521,7 @@ err_unlock: err_sens: v4l2_device_unregister(&camif->v4l2_dev); media_device_unregister(&camif->media_dev); + media_device_cleanup(&camif->media_dev); camif_unregister_media_entities(camif); err_mdev: vb2_dma_contig_cleanup_ctx(camif->alloc_ctx); @@ -539,6 +543,7 @@ static int s3c_camif_remove(struct platform_device *pdev) struct s3c_camif_plat_data *pdata = &camif->pdata; media_device_unregister(&camif->media_dev); + media_device_cleanup(&camif->media_dev); camif_unregister_media_entities(camif); v4l2_device_unregister(&camif->v4l2_dev); diff --git a/drivers/media/platform/s3c-camif/camif-core.h b/drivers/media/platform/s3c-camif/camif-core.h index adaf1969e..57cbc3d97 100644 --- a/drivers/media/platform/s3c-camif/camif-core.h +++ b/drivers/media/platform/s3c-camif/camif-core.h @@ -26,7 +26,7 @@ #include <media/v4l2-device.h> #include <media/v4l2-mediabus.h> #include <media/videobuf2-v4l2.h> -#include <media/s3c_camif.h> +#include <media/drv-intf/s3c_camif.h> #define S3C_CAMIF_DRIVER_NAME "s3c-camif" #define CAMIF_REQ_BUFS_MIN 3 diff --git a/drivers/media/platform/s3c-camif/camif-regs.h b/drivers/media/platform/s3c-camif/camif-regs.h index af2d472ea..5ad36c1c2 100644 --- a/drivers/media/platform/s3c-camif/camif-regs.h +++ b/drivers/media/platform/s3c-camif/camif-regs.h @@ -13,7 +13,7 @@ #define CAMIF_REGS_H_ #include "camif-core.h" -#include <media/s3c_camif.h> +#include <media/drv-intf/s3c_camif.h> /* * The id argument indicates the processing path: diff --git a/drivers/media/platform/s5p-g2d/g2d.c b/drivers/media/platform/s5p-g2d/g2d.c index e1936d9d2..74bd46ca7 100644 --- a/drivers/media/platform/s5p-g2d/g2d.c +++ b/drivers/media/platform/s5p-g2d/g2d.c @@ -101,7 +101,7 @@ static struct g2d_frame *get_frame(struct g2d_ctx *ctx, } } -static int g2d_queue_setup(struct vb2_queue *vq, const void *parg, +static int g2d_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) { @@ -552,7 +552,7 @@ static irqreturn_t g2d_isr(int irq, void *prv) BUG_ON(dst == NULL); dst->timecode = src->timecode; - dst->timestamp = src->timestamp; + dst->vb2_buf.timestamp = src->vb2_buf.timestamp; dst->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; dst->flags |= src->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK; diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c index 4a608cbe0..c3b13a630 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-core.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c @@ -2430,7 +2430,6 @@ static struct v4l2_m2m_ops exynos4_jpeg_m2m_ops = { */ static int s5p_jpeg_queue_setup(struct vb2_queue *vq, - const void *parg, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) { @@ -2621,7 +2620,7 @@ static irqreturn_t s5p_jpeg_irq(int irq, void *dev_id) } dst_buf->timecode = src_buf->timecode; - dst_buf->timestamp = src_buf->timestamp; + dst_buf->vb2_buf.timestamp = src_buf->vb2_buf.timestamp; dst_buf->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; dst_buf->flags |= src_buf->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK; @@ -2752,7 +2751,7 @@ static irqreturn_t exynos3250_jpeg_irq(int irq, void *dev_id) dst_buf = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx); dst_buf->timecode = src_buf->timecode; - dst_buf->timestamp = src_buf->timestamp; + dst_buf->vb2_buf.timestamp = src_buf->vb2_buf.timestamp; v4l2_m2m_buf_done(src_buf, state); if (curr_ctx->mode == S5P_JPEG_ENCODE) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 650f10173..d83bbf529 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -85,6 +85,26 @@ void set_work_bit_irqsave(struct s5p_mfc_ctx *ctx) spin_unlock_irqrestore(&dev->condlock, flags); } +int s5p_mfc_get_new_ctx(struct s5p_mfc_dev *dev) +{ + unsigned long flags; + int ctx; + + spin_lock_irqsave(&dev->condlock, flags); + ctx = dev->curr_ctx; + do { + ctx = (ctx + 1) % MFC_NUM_CONTEXTS; + if (ctx == dev->curr_ctx) { + if (!test_bit(ctx, &dev->ctx_work_bits)) + ctx = -EAGAIN; + break; + } + } while (!test_bit(ctx, &dev->ctx_work_bits)); + spin_unlock_irqrestore(&dev->condlock, flags); + + return ctx; +} + /* Wake up context wait_queue */ static void wake_up_ctx(struct s5p_mfc_ctx *ctx, unsigned int reason, unsigned int err) @@ -105,6 +125,20 @@ static void wake_up_dev(struct s5p_mfc_dev *dev, unsigned int reason, wake_up(&dev->queue); } +void s5p_mfc_cleanup_queue(struct list_head *lh, struct vb2_queue *vq) +{ + struct s5p_mfc_buf *b; + int i; + + while (!list_empty(lh)) { + b = list_entry(lh->next, struct s5p_mfc_buf, list); + for (i = 0; i < b->b->vb2_buf.num_planes; i++) + vb2_set_plane_payload(&b->b->vb2_buf, i, 0); + vb2_buffer_done(&b->b->vb2_buf, VB2_BUF_STATE_ERROR); + list_del(&b->list); + } +} + static void s5p_mfc_watchdog(unsigned long arg) { struct s5p_mfc_dev *dev = (struct s5p_mfc_dev *)arg; @@ -150,10 +184,8 @@ static void s5p_mfc_watchdog_worker(struct work_struct *work) if (!ctx) continue; ctx->state = MFCINST_ERROR; - s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue, - &ctx->dst_queue, &ctx->vq_dst); - s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue, - &ctx->src_queue, &ctx->vq_src); + s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst); + s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src); clear_work_bit(ctx); wake_up_ctx(ctx, S5P_MFC_R2H_CMD_ERR_RET, 0); } @@ -233,8 +265,8 @@ static void s5p_mfc_handle_frame_copy_time(struct s5p_mfc_ctx *ctx) == dec_y_addr) { dst_buf->b->timecode = src_buf->b->timecode; - dst_buf->b->timestamp = - src_buf->b->timestamp; + dst_buf->b->vb2_buf.timestamp = + src_buf->b->vb2_buf.timestamp; dst_buf->b->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; dst_buf->b->flags |= @@ -327,7 +359,6 @@ static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx, unsigned int dst_frame_status; unsigned int dec_frame_status; struct s5p_mfc_buf *src_buf; - unsigned long flags; unsigned int res_change; dst_frame_status = s5p_mfc_hw_call(dev->mfc_ops, get_dspl_status, dev) @@ -343,17 +374,16 @@ static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx, if (res_change == S5P_FIMV_RES_INCREASE || res_change == S5P_FIMV_RES_DECREASE) { ctx->state = MFCINST_RES_CHANGE_INIT; - s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev); + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); wake_up_ctx(ctx, reason, err); WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0); s5p_mfc_clock_off(); - s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); return; } if (ctx->dpb_flush_flag) ctx->dpb_flush_flag = 0; - spin_lock_irqsave(&dev->irqlock, flags); /* All frames remaining in the buffer have been extracted */ if (dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_EMPTY) { if (ctx->state == MFCINST_RES_CHANGE_FLUSH) { @@ -413,11 +443,10 @@ static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx, } } leave_handle_frame: - spin_unlock_irqrestore(&dev->irqlock, flags); if ((ctx->src_queue_cnt == 0 && ctx->state != MFCINST_FINISHING) || ctx->dst_queue_cnt < ctx->pb_count) clear_work_bit(ctx); - s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev); + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); wake_up_ctx(ctx, reason, err); WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0); s5p_mfc_clock_off(); @@ -425,15 +454,13 @@ leave_handle_frame: if (test_bit(0, &dev->enter_suspend)) wake_up_dev(dev, reason, err); else - s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); } /* Error handling for interrupt */ static void s5p_mfc_handle_error(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx, unsigned int reason, unsigned int err) { - unsigned long flags; - mfc_err("Interrupt Error: %08x\n", err); if (ctx != NULL) { @@ -450,13 +477,9 @@ static void s5p_mfc_handle_error(struct s5p_mfc_dev *dev, clear_work_bit(ctx); ctx->state = MFCINST_ERROR; /* Mark all dst buffers as having an error */ - spin_lock_irqsave(&dev->irqlock, flags); - s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue, - &ctx->dst_queue, &ctx->vq_dst); + s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst); /* Mark all src buffers as having an error */ - s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue, - &ctx->src_queue, &ctx->vq_src); - spin_unlock_irqrestore(&dev->irqlock, flags); + s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src); wake_up_ctx(ctx, reason, err); break; default: @@ -467,7 +490,7 @@ static void s5p_mfc_handle_error(struct s5p_mfc_dev *dev, } } WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0); - s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev); + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); s5p_mfc_clock_off(); wake_up_dev(dev, reason, err); return; @@ -491,7 +514,7 @@ static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx, ctx->img_height = s5p_mfc_hw_call(dev->mfc_ops, get_img_height, dev); - s5p_mfc_hw_call_void(dev->mfc_ops, dec_calc_dpb_size, ctx); + s5p_mfc_hw_call(dev->mfc_ops, dec_calc_dpb_size, ctx); ctx->pb_count = s5p_mfc_hw_call(dev->mfc_ops, get_dpb_count, dev); @@ -518,11 +541,11 @@ static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx, ctx->head_processed = 1; } } - s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev); + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); clear_work_bit(ctx); WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0); s5p_mfc_clock_off(); - s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); wake_up_ctx(ctx, reason, err); } @@ -532,12 +555,11 @@ static void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx, { struct s5p_mfc_buf *src_buf; struct s5p_mfc_dev *dev; - unsigned long flags; if (ctx == NULL) return; dev = ctx->dev; - s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev); + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); ctx->int_type = reason; ctx->int_err = err; ctx->int_cond = 1; @@ -545,7 +567,6 @@ static void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx, if (err == 0) { ctx->state = MFCINST_RUNNING; if (!ctx->dpb_flush_flag && ctx->head_processed) { - spin_lock_irqsave(&dev->irqlock, flags); if (!list_empty(&ctx->src_queue)) { src_buf = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); @@ -554,7 +575,6 @@ static void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx, vb2_buffer_done(&src_buf->b->vb2_buf, VB2_BUF_STATE_DONE); } - spin_unlock_irqrestore(&dev->irqlock, flags); } else { ctx->dpb_flush_flag = 0; } @@ -563,7 +583,7 @@ static void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx, s5p_mfc_clock_off(); wake_up(&ctx->queue); - s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); } else { WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0); @@ -582,7 +602,6 @@ static void s5p_mfc_handle_stream_complete(struct s5p_mfc_ctx *ctx) ctx->state = MFCINST_FINISHED; - spin_lock(&dev->irqlock); if (!list_empty(&ctx->dst_queue)) { mb_entry = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); @@ -591,7 +610,6 @@ static void s5p_mfc_handle_stream_complete(struct s5p_mfc_ctx *ctx) vb2_set_plane_payload(&mb_entry->b->vb2_buf, 0, 0); vb2_buffer_done(&mb_entry->b->vb2_buf, VB2_BUF_STATE_DONE); } - spin_unlock(&dev->irqlock); clear_work_bit(ctx); @@ -599,7 +617,7 @@ static void s5p_mfc_handle_stream_complete(struct s5p_mfc_ctx *ctx) s5p_mfc_clock_off(); wake_up(&ctx->queue); - s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); } /* Interrupt processing */ @@ -613,6 +631,7 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv) mfc_debug_enter(); /* Reset the timeout watchdog */ atomic_set(&dev->watchdog_cnt, 0); + spin_lock(&dev->irqlock); ctx = dev->ctx[dev->curr_ctx]; /* Get the reason of interrupt and the error code */ reason = s5p_mfc_hw_call(dev->mfc_ops, get_int_reason, dev); @@ -639,15 +658,15 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv) if (ctx->state == MFCINST_FINISHING && list_empty(&ctx->ref_queue)) { - s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev); + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); s5p_mfc_handle_stream_complete(ctx); break; } - s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev); + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); wake_up_ctx(ctx, reason, err); WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0); s5p_mfc_clock_off(); - s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); } else { s5p_mfc_handle_frame(ctx, reason, err); } @@ -677,7 +696,7 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv) case S5P_MFC_R2H_CMD_WAKEUP_RET: if (ctx) clear_work_bit(ctx); - s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev); + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); wake_up_dev(dev, reason, err); clear_bit(0, &dev->hw_lock); clear_bit(0, &dev->enter_suspend); @@ -688,7 +707,7 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv) break; case S5P_MFC_R2H_CMD_COMPLETE_SEQ_RET: - s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev); + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); ctx->int_type = reason; ctx->int_err = err; s5p_mfc_handle_stream_complete(ctx); @@ -702,12 +721,13 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv) default: mfc_debug(2, "Unknown int reason\n"); - s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev); + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); } + spin_unlock(&dev->irqlock); mfc_debug_leave(); return IRQ_HANDLED; irq_cleanup_hw: - s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev); + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); ctx->int_type = reason; ctx->int_err = err; ctx->int_cond = 1; @@ -716,7 +736,8 @@ irq_cleanup_hw: s5p_mfc_clock_off(); - s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); + spin_unlock(&dev->irqlock); mfc_debug(2, "Exit via irq_cleanup_hw\n"); return IRQ_HANDLED; } diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h index d1a3f9b1b..9eb2481ec 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h @@ -308,7 +308,7 @@ struct s5p_mfc_dev { struct s5p_mfc_pm pm; struct s5p_mfc_variant *variant; int num_inst; - spinlock_t irqlock; /* lock when operating on videobuf2 queues */ + spinlock_t irqlock; /* lock when operating on context */ spinlock_t condlock; /* lock when changing/checking if a context is ready to be processed */ struct mutex mfc_mutex; /* video_device lock */ @@ -653,7 +653,7 @@ struct s5p_mfc_ctx { unsigned int bits; } slice_size; - struct s5p_mfc_codec_ops *c_ops; + const struct s5p_mfc_codec_ops *c_ops; struct v4l2_ctrl *ctrls[MFC_MAX_CTRLS]; struct v4l2_ctrl_handler ctrl_handler; @@ -694,13 +694,7 @@ struct mfc_control { /* Macro for making hardware specific calls */ #define s5p_mfc_hw_call(f, op, args...) \ - ((f && f->op) ? f->op(args) : -ENODEV) - -#define s5p_mfc_hw_call_void(f, op, args...) \ -do { \ - if (f && f->op) \ - f->op(args); \ -} while (0) + ((f && f->op) ? f->op(args) : (typeof(f->op(args)))(-ENODEV)) #define fh_to_ctx(__fh) container_of(__fh, struct s5p_mfc_ctx, fh) #define ctrl_to_ctx(__ctrl) \ @@ -710,6 +704,8 @@ void clear_work_bit(struct s5p_mfc_ctx *ctx); void set_work_bit(struct s5p_mfc_ctx *ctx); void clear_work_bit_irqsave(struct s5p_mfc_ctx *ctx); void set_work_bit_irqsave(struct s5p_mfc_ctx *ctx); +int s5p_mfc_get_new_ctx(struct s5p_mfc_dev *dev); +void s5p_mfc_cleanup_queue(struct list_head *lh, struct vb2_queue *vq); #define HAS_PORTNUM(dev) (dev ? (dev->variant ? \ (dev->variant->port_num ? 1 : 0) : 0) : 0) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c index 65ab660e9..73ba5472b 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c @@ -319,7 +319,7 @@ void s5p_mfc_deinit_hw(struct s5p_mfc_dev *dev) s5p_mfc_clock_on(); s5p_mfc_reset(dev); - s5p_mfc_hw_call_void(dev->mfc_ops, release_dev_context_buffer, dev); + s5p_mfc_hw_call(dev->mfc_ops, release_dev_context_buffer, dev); s5p_mfc_clock_off(); } @@ -468,7 +468,7 @@ int s5p_mfc_open_mfc_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx) } set_work_bit_irqsave(ctx); - s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); if (s5p_mfc_wait_for_done_ctx(ctx, S5P_MFC_R2H_CMD_OPEN_INSTANCE_RET, 0)) { /* Error or timeout */ @@ -482,9 +482,9 @@ int s5p_mfc_open_mfc_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx) err_free_desc_buf: if (ctx->type == MFCINST_DECODER) - s5p_mfc_hw_call_void(dev->mfc_ops, release_dec_desc_buffer, ctx); + s5p_mfc_hw_call(dev->mfc_ops, release_dec_desc_buffer, ctx); err_free_inst_buf: - s5p_mfc_hw_call_void(dev->mfc_ops, release_instance_buffer, ctx); + s5p_mfc_hw_call(dev->mfc_ops, release_instance_buffer, ctx); err: return ret; } @@ -493,17 +493,17 @@ void s5p_mfc_close_mfc_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx) { ctx->state = MFCINST_RETURN_INST; set_work_bit_irqsave(ctx); - s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); /* Wait until instance is returned or timeout occurred */ if (s5p_mfc_wait_for_done_ctx(ctx, S5P_MFC_R2H_CMD_CLOSE_INSTANCE_RET, 0)) mfc_err("Err returning instance\n"); /* Free resources */ - s5p_mfc_hw_call_void(dev->mfc_ops, release_codec_buffers, ctx); - s5p_mfc_hw_call_void(dev->mfc_ops, release_instance_buffer, ctx); + s5p_mfc_hw_call(dev->mfc_ops, release_codec_buffers, ctx); + s5p_mfc_hw_call(dev->mfc_ops, release_instance_buffer, ctx); if (ctx->type == MFCINST_DECODER) - s5p_mfc_hw_call_void(dev->mfc_ops, release_dec_desc_buffer, ctx); + s5p_mfc_hw_call(dev->mfc_ops, release_dec_desc_buffer, ctx); ctx->inst_no = MFC_NO_INSTANCE_SET; ctx->state = MFCINST_FREE; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c index 8c5060a75..f2d6376ce 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c @@ -252,7 +252,7 @@ static int s5p_mfc_ctx_ready(struct s5p_mfc_ctx *ctx) return 0; } -static struct s5p_mfc_codec_ops decoder_codec_ops = { +static const struct s5p_mfc_codec_ops decoder_codec_ops = { .pre_seq_start = NULL, .post_seq_start = NULL, .pre_frame_start = NULL, @@ -523,7 +523,7 @@ static int reqbufs_capture(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx, ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); if (ret) goto out; - s5p_mfc_hw_call_void(dev->mfc_ops, release_codec_buffers, ctx); + s5p_mfc_hw_call(dev->mfc_ops, release_codec_buffers, ctx); ctx->dst_bufs_cnt = 0; } else if (ctx->capture_state == QUEUE_FREE) { WARN_ON(ctx->dst_bufs_cnt != 0); @@ -551,7 +551,7 @@ static int reqbufs_capture(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx, if (s5p_mfc_ctx_ready(ctx)) set_work_bit_irqsave(ctx); - s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); s5p_mfc_wait_for_done_ctx(ctx, S5P_MFC_R2H_CMD_INIT_BUFFERS_RET, 0); } else { @@ -831,7 +831,7 @@ static int vidioc_decoder_cmd(struct file *file, void *priv, if (s5p_mfc_ctx_ready(ctx)) set_work_bit_irqsave(ctx); spin_unlock_irqrestore(&dev->irqlock, flags); - s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); } else { mfc_err("EOS: marking last buffer of stream"); buf = list_entry(ctx->src_queue.prev, @@ -888,7 +888,7 @@ static const struct v4l2_ioctl_ops s5p_mfc_dec_ioctl_ops = { }; static int s5p_mfc_queue_setup(struct vb2_queue *vq, - const void *parg, unsigned int *buf_count, + unsigned int *buf_count, unsigned int *plane_count, unsigned int psize[], void *allocators[]) { @@ -1012,7 +1012,7 @@ static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count) /* If context is ready then dev = work->data;schedule it to run */ if (s5p_mfc_ctx_ready(ctx)) set_work_bit_irqsave(ctx); - s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); return 0; } @@ -1023,42 +1023,41 @@ static void s5p_mfc_stop_streaming(struct vb2_queue *q) struct s5p_mfc_dev *dev = ctx->dev; int aborted = 0; + spin_lock_irqsave(&dev->irqlock, flags); if ((ctx->state == MFCINST_FINISHING || ctx->state == MFCINST_RUNNING) && dev->curr_ctx == ctx->num && dev->hw_lock) { ctx->state = MFCINST_ABORT; + spin_unlock_irqrestore(&dev->irqlock, flags); s5p_mfc_wait_for_done_ctx(ctx, S5P_MFC_R2H_CMD_FRAME_DONE_RET, 0); aborted = 1; + spin_lock_irqsave(&dev->irqlock, flags); } if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - spin_lock_irqsave(&dev->irqlock, flags); - s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue, - &ctx->dst_queue, &ctx->vq_dst); + s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst); INIT_LIST_HEAD(&ctx->dst_queue); ctx->dst_queue_cnt = 0; ctx->dpb_flush_flag = 1; ctx->dec_dst_flag = 0; - spin_unlock_irqrestore(&dev->irqlock, flags); if (IS_MFCV6_PLUS(dev) && (ctx->state == MFCINST_RUNNING)) { ctx->state = MFCINST_FLUSH; set_work_bit_irqsave(ctx); - s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); + spin_unlock_irqrestore(&dev->irqlock, flags); if (s5p_mfc_wait_for_done_ctx(ctx, S5P_MFC_R2H_CMD_DPB_FLUSH_RET, 0)) mfc_err("Err flushing buffers\n"); + spin_lock_irqsave(&dev->irqlock, flags); } - } - if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - spin_lock_irqsave(&dev->irqlock, flags); - s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue, - &ctx->src_queue, &ctx->vq_src); + } else if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src); INIT_LIST_HEAD(&ctx->src_queue); ctx->src_queue_cnt = 0; - spin_unlock_irqrestore(&dev->irqlock, flags); } if (aborted) ctx->state = MFCINST_RUNNING; + spin_unlock_irqrestore(&dev->irqlock, flags); } @@ -1091,7 +1090,7 @@ static void s5p_mfc_buf_queue(struct vb2_buffer *vb) } if (s5p_mfc_ctx_ready(ctx)) set_work_bit_irqsave(ctx); - s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); } static struct vb2_ops s5p_mfc_dec_qops = { @@ -1104,7 +1103,7 @@ static struct vb2_ops s5p_mfc_dec_qops = { .buf_queue = s5p_mfc_buf_queue, }; -struct s5p_mfc_codec_ops *get_dec_codec_ops(void) +const struct s5p_mfc_codec_ops *get_dec_codec_ops(void) { return &decoder_codec_ops; } @@ -1119,7 +1118,7 @@ const struct v4l2_ioctl_ops *get_dec_v4l2_ioctl_ops(void) return &s5p_mfc_dec_ioctl_ops; } -#define IS_MFC51_PRIV(x) ((V4L2_CTRL_ID2CLASS(x) == V4L2_CTRL_CLASS_MPEG) \ +#define IS_MFC51_PRIV(x) ((V4L2_CTRL_ID2WHICH(x) == V4L2_CTRL_CLASS_MPEG) \ && V4L2_CTRL_DRIVER_PRIV(x)) int s5p_mfc_dec_ctrls_setup(struct s5p_mfc_ctx *ctx) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.h b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.h index d06a7cab5..886628b15 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.h @@ -13,7 +13,7 @@ #ifndef S5P_MFC_DEC_H_ #define S5P_MFC_DEC_H_ -struct s5p_mfc_codec_ops *get_dec_codec_ops(void); +const struct s5p_mfc_codec_ops *get_dec_codec_ops(void); struct vb2_ops *get_dec_queue_ops(void); const struct v4l2_ioctl_ops *get_dec_v4l2_ioctl_ops(void); struct s5p_mfc_fmt *get_dec_def_fmt(bool src); diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c index 5c678ec9c..0434f02a7 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c @@ -769,15 +769,12 @@ static int enc_pre_seq_start(struct s5p_mfc_ctx *ctx) struct s5p_mfc_buf *dst_mb; unsigned long dst_addr; unsigned int dst_size; - unsigned long flags; - spin_lock_irqsave(&dev->irqlock, flags); dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); dst_addr = vb2_dma_contig_plane_dma_addr(&dst_mb->b->vb2_buf, 0); dst_size = vb2_plane_size(&dst_mb->b->vb2_buf, 0); - s5p_mfc_hw_call_void(dev->mfc_ops, set_enc_stream_buffer, ctx, dst_addr, + s5p_mfc_hw_call(dev->mfc_ops, set_enc_stream_buffer, ctx, dst_addr, dst_size); - spin_unlock_irqrestore(&dev->irqlock, flags); return 0; } @@ -786,11 +783,9 @@ static int enc_post_seq_start(struct s5p_mfc_ctx *ctx) struct s5p_mfc_dev *dev = ctx->dev; struct s5p_mfc_enc_params *p = &ctx->enc_params; struct s5p_mfc_buf *dst_mb; - unsigned long flags; unsigned int enc_pb_count; if (p->seq_hdr_mode == V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) { - spin_lock_irqsave(&dev->irqlock, flags); if (!list_empty(&ctx->dst_queue)) { dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); @@ -802,14 +797,13 @@ static int enc_post_seq_start(struct s5p_mfc_ctx *ctx) vb2_buffer_done(&dst_mb->b->vb2_buf, VB2_BUF_STATE_DONE); } - spin_unlock_irqrestore(&dev->irqlock, flags); } if (!IS_MFCV6_PLUS(dev)) { ctx->state = MFCINST_RUNNING; if (s5p_mfc_ctx_ready(ctx)) set_work_bit_irqsave(ctx); - s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); } else { enc_pb_count = s5p_mfc_hw_call(dev->mfc_ops, get_enc_dpb_count, dev); @@ -826,25 +820,20 @@ static int enc_pre_frame_start(struct s5p_mfc_ctx *ctx) struct s5p_mfc_dev *dev = ctx->dev; struct s5p_mfc_buf *dst_mb; struct s5p_mfc_buf *src_mb; - unsigned long flags; unsigned long src_y_addr, src_c_addr, dst_addr; unsigned int dst_size; - spin_lock_irqsave(&dev->irqlock, flags); src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); src_y_addr = vb2_dma_contig_plane_dma_addr(&src_mb->b->vb2_buf, 0); src_c_addr = vb2_dma_contig_plane_dma_addr(&src_mb->b->vb2_buf, 1); - s5p_mfc_hw_call_void(dev->mfc_ops, set_enc_frame_buffer, ctx, + s5p_mfc_hw_call(dev->mfc_ops, set_enc_frame_buffer, ctx, src_y_addr, src_c_addr); - spin_unlock_irqrestore(&dev->irqlock, flags); - spin_lock_irqsave(&dev->irqlock, flags); dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); dst_addr = vb2_dma_contig_plane_dma_addr(&dst_mb->b->vb2_buf, 0); dst_size = vb2_plane_size(&dst_mb->b->vb2_buf, 0); - s5p_mfc_hw_call_void(dev->mfc_ops, set_enc_stream_buffer, ctx, dst_addr, + s5p_mfc_hw_call(dev->mfc_ops, set_enc_stream_buffer, ctx, dst_addr, dst_size); - spin_unlock_irqrestore(&dev->irqlock, flags); return 0; } @@ -857,7 +846,6 @@ static int enc_post_frame_start(struct s5p_mfc_ctx *ctx) unsigned long mb_y_addr, mb_c_addr; int slice_type; unsigned int strm_size; - unsigned long flags; slice_type = s5p_mfc_hw_call(dev->mfc_ops, get_enc_slice_type, dev); strm_size = s5p_mfc_hw_call(dev->mfc_ops, get_enc_strm_size, dev); @@ -865,9 +853,8 @@ static int enc_post_frame_start(struct s5p_mfc_ctx *ctx) mfc_debug(2, "Encoded stream size: %d\n", strm_size); mfc_debug(2, "Display order: %d\n", mfc_read(dev, S5P_FIMV_ENC_SI_PIC_CNT)); - spin_lock_irqsave(&dev->irqlock, flags); if (slice_type >= 0) { - s5p_mfc_hw_call_void(dev->mfc_ops, get_enc_frame_buffer, ctx, + s5p_mfc_hw_call(dev->mfc_ops, get_enc_frame_buffer, ctx, &enc_y_addr, &enc_c_addr); list_for_each_entry(mb_entry, &ctx->src_queue, list) { mb_y_addr = vb2_dma_contig_plane_dma_addr( @@ -929,14 +916,13 @@ static int enc_post_frame_start(struct s5p_mfc_ctx *ctx) vb2_set_plane_payload(&mb_entry->b->vb2_buf, 0, strm_size); vb2_buffer_done(&mb_entry->b->vb2_buf, VB2_BUF_STATE_DONE); } - spin_unlock_irqrestore(&dev->irqlock, flags); if ((ctx->src_queue_cnt == 0) || (ctx->dst_queue_cnt == 0)) clear_work_bit(ctx); return 0; } -static struct s5p_mfc_codec_ops encoder_codec_ops = { +static const struct s5p_mfc_codec_ops encoder_codec_ops = { .pre_seq_start = enc_pre_seq_start, .post_seq_start = enc_post_seq_start, .pre_frame_start = enc_pre_frame_start, @@ -1120,7 +1106,7 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) pix_fmt_mp->width, pix_fmt_mp->height, ctx->img_width, ctx->img_height); - s5p_mfc_hw_call_void(dev->mfc_ops, enc_calc_src_size, ctx); + s5p_mfc_hw_call(dev->mfc_ops, enc_calc_src_size, ctx); pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size; pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width; pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size; @@ -1178,7 +1164,7 @@ static int vidioc_reqbufs(struct file *file, void *priv, if (reqbufs->count == 0) { mfc_debug(2, "Freeing buffers\n"); ret = vb2_reqbufs(&ctx->vq_src, reqbufs); - s5p_mfc_hw_call_void(dev->mfc_ops, release_codec_buffers, + s5p_mfc_hw_call(dev->mfc_ops, release_codec_buffers, ctx); ctx->output_state = QUEUE_FREE; return ret; @@ -1741,7 +1727,7 @@ static int vidioc_encoder_cmd(struct file *file, void *priv, if (s5p_mfc_ctx_ready(ctx)) set_work_bit_irqsave(ctx); spin_unlock_irqrestore(&dev->irqlock, flags); - s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); } else { mfc_debug(2, "EOS: marking last buffer of stream\n"); buf = list_entry(ctx->src_queue.prev, @@ -1818,7 +1804,6 @@ static int check_vb_with_fmt(struct s5p_mfc_fmt *fmt, struct vb2_buffer *vb) } static int s5p_mfc_queue_setup(struct vb2_queue *vq, - const void *parg, unsigned int *buf_count, unsigned int *plane_count, unsigned int psize[], void *allocators[]) { @@ -1969,7 +1954,7 @@ static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count) /* If context is ready then dev = work->data;schedule it to run */ if (s5p_mfc_ctx_ready(ctx)) set_work_bit_irqsave(ctx); - s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); return 0; } @@ -1990,15 +1975,13 @@ static void s5p_mfc_stop_streaming(struct vb2_queue *q) ctx->state = MFCINST_FINISHED; spin_lock_irqsave(&dev->irqlock, flags); if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue, - &ctx->dst_queue, &ctx->vq_dst); + s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst); INIT_LIST_HEAD(&ctx->dst_queue); ctx->dst_queue_cnt = 0; } if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { cleanup_ref_queue(ctx); - s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue, &ctx->src_queue, - &ctx->vq_src); + s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src); INIT_LIST_HEAD(&ctx->src_queue); ctx->src_queue_cnt = 0; } @@ -2038,7 +2021,7 @@ static void s5p_mfc_buf_queue(struct vb2_buffer *vb) } if (s5p_mfc_ctx_ready(ctx)) set_work_bit_irqsave(ctx); - s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); } static struct vb2_ops s5p_mfc_enc_qops = { @@ -2052,7 +2035,7 @@ static struct vb2_ops s5p_mfc_enc_qops = { .buf_queue = s5p_mfc_buf_queue, }; -struct s5p_mfc_codec_ops *get_enc_codec_ops(void) +const struct s5p_mfc_codec_ops *get_enc_codec_ops(void) { return &encoder_codec_ops; } @@ -2067,7 +2050,7 @@ const struct v4l2_ioctl_ops *get_enc_v4l2_ioctl_ops(void) return &s5p_mfc_enc_ioctl_ops; } -#define IS_MFC51_PRIV(x) ((V4L2_CTRL_ID2CLASS(x) == V4L2_CTRL_CLASS_MPEG) \ +#define IS_MFC51_PRIV(x) ((V4L2_CTRL_ID2WHICH(x) == V4L2_CTRL_CLASS_MPEG) \ && V4L2_CTRL_DRIVER_PRIV(x)) int s5p_mfc_enc_ctrls_setup(struct s5p_mfc_ctx *ctx) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.h b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.h index 5118d46b3..d0d42f818 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.h @@ -13,7 +13,7 @@ #ifndef S5P_MFC_ENC_H_ #define S5P_MFC_ENC_H_ -struct s5p_mfc_codec_ops *get_enc_codec_ops(void); +const struct s5p_mfc_codec_ops *get_enc_codec_ops(void); struct vb2_ops *get_enc_queue_ops(void); const struct v4l2_ioctl_ops *get_enc_v4l2_ioctl_ops(void); struct s5p_mfc_fmt *get_enc_def_fmt(bool src); diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h index 77a08b19b..b6ac417ab 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h @@ -20,254 +20,254 @@ struct s5p_mfc_regs { /* codec common registers */ - volatile void __iomem *risc_on; - volatile void __iomem *risc2host_int; - volatile void __iomem *host2risc_int; - volatile void __iomem *risc_base_address; - volatile void __iomem *mfc_reset; - volatile void __iomem *host2risc_command; - volatile void __iomem *risc2host_command; - volatile void __iomem *mfc_bus_reset_ctrl; - volatile void __iomem *firmware_version; - volatile void __iomem *instance_id; - volatile void __iomem *codec_type; - volatile void __iomem *context_mem_addr; - volatile void __iomem *context_mem_size; - volatile void __iomem *pixel_format; - volatile void __iomem *metadata_enable; - volatile void __iomem *mfc_version; - volatile void __iomem *dbg_info_enable; - volatile void __iomem *dbg_buffer_addr; - volatile void __iomem *dbg_buffer_size; - volatile void __iomem *hed_control; - volatile void __iomem *mfc_timeout_value; - volatile void __iomem *hed_shared_mem_addr; - volatile void __iomem *dis_shared_mem_addr;/* only v7 */ - volatile void __iomem *ret_instance_id; - volatile void __iomem *error_code; - volatile void __iomem *dbg_buffer_output_size; - volatile void __iomem *metadata_status; - volatile void __iomem *metadata_addr_mb_info; - volatile void __iomem *metadata_size_mb_info; - volatile void __iomem *dbg_info_stage_counter; + void __iomem *risc_on; + void __iomem *risc2host_int; + void __iomem *host2risc_int; + void __iomem *risc_base_address; + void __iomem *mfc_reset; + void __iomem *host2risc_command; + void __iomem *risc2host_command; + void __iomem *mfc_bus_reset_ctrl; + void __iomem *firmware_version; + void __iomem *instance_id; + void __iomem *codec_type; + void __iomem *context_mem_addr; + void __iomem *context_mem_size; + void __iomem *pixel_format; + void __iomem *metadata_enable; + void __iomem *mfc_version; + void __iomem *dbg_info_enable; + void __iomem *dbg_buffer_addr; + void __iomem *dbg_buffer_size; + void __iomem *hed_control; + void __iomem *mfc_timeout_value; + void __iomem *hed_shared_mem_addr; + void __iomem *dis_shared_mem_addr;/* only v7 */ + void __iomem *ret_instance_id; + void __iomem *error_code; + void __iomem *dbg_buffer_output_size; + void __iomem *metadata_status; + void __iomem *metadata_addr_mb_info; + void __iomem *metadata_size_mb_info; + void __iomem *dbg_info_stage_counter; /* decoder registers */ - volatile void __iomem *d_crc_ctrl; - volatile void __iomem *d_dec_options; - volatile void __iomem *d_display_delay; - volatile void __iomem *d_set_frame_width; - volatile void __iomem *d_set_frame_height; - volatile void __iomem *d_sei_enable; - volatile void __iomem *d_min_num_dpb; - volatile void __iomem *d_min_first_plane_dpb_size; - volatile void __iomem *d_min_second_plane_dpb_size; - volatile void __iomem *d_min_third_plane_dpb_size;/* only v8 */ - volatile void __iomem *d_min_num_mv; - volatile void __iomem *d_mvc_num_views; - volatile void __iomem *d_min_num_dis;/* only v7 */ - volatile void __iomem *d_min_first_dis_size;/* only v7 */ - volatile void __iomem *d_min_second_dis_size;/* only v7 */ - volatile void __iomem *d_min_third_dis_size;/* only v7 */ - volatile void __iomem *d_post_filter_luma_dpb0;/* v7 and v8 */ - volatile void __iomem *d_post_filter_luma_dpb1;/* v7 and v8 */ - volatile void __iomem *d_post_filter_luma_dpb2;/* only v7 */ - volatile void __iomem *d_post_filter_chroma_dpb0;/* v7 and v8 */ - volatile void __iomem *d_post_filter_chroma_dpb1;/* v7 and v8 */ - volatile void __iomem *d_post_filter_chroma_dpb2;/* only v7 */ - volatile void __iomem *d_num_dpb; - volatile void __iomem *d_num_mv; - volatile void __iomem *d_init_buffer_options; - volatile void __iomem *d_first_plane_dpb_stride_size;/* only v8 */ - volatile void __iomem *d_second_plane_dpb_stride_size;/* only v8 */ - volatile void __iomem *d_third_plane_dpb_stride_size;/* only v8 */ - volatile void __iomem *d_first_plane_dpb_size; - volatile void __iomem *d_second_plane_dpb_size; - volatile void __iomem *d_third_plane_dpb_size;/* only v8 */ - volatile void __iomem *d_mv_buffer_size; - volatile void __iomem *d_first_plane_dpb; - volatile void __iomem *d_second_plane_dpb; - volatile void __iomem *d_third_plane_dpb; - volatile void __iomem *d_mv_buffer; - volatile void __iomem *d_scratch_buffer_addr; - volatile void __iomem *d_scratch_buffer_size; - volatile void __iomem *d_metadata_buffer_addr; - volatile void __iomem *d_metadata_buffer_size; - volatile void __iomem *d_nal_start_options;/* v7 and v8 */ - volatile void __iomem *d_cpb_buffer_addr; - volatile void __iomem *d_cpb_buffer_size; - volatile void __iomem *d_available_dpb_flag_upper; - volatile void __iomem *d_available_dpb_flag_lower; - volatile void __iomem *d_cpb_buffer_offset; - volatile void __iomem *d_slice_if_enable; - volatile void __iomem *d_picture_tag; - volatile void __iomem *d_stream_data_size; - volatile void __iomem *d_dynamic_dpb_flag_upper;/* v7 and v8 */ - volatile void __iomem *d_dynamic_dpb_flag_lower;/* v7 and v8 */ - volatile void __iomem *d_display_frame_width; - volatile void __iomem *d_display_frame_height; - volatile void __iomem *d_display_status; - volatile void __iomem *d_display_first_plane_addr; - volatile void __iomem *d_display_second_plane_addr; - volatile void __iomem *d_display_third_plane_addr;/* only v8 */ - volatile void __iomem *d_display_frame_type; - volatile void __iomem *d_display_crop_info1; - volatile void __iomem *d_display_crop_info2; - volatile void __iomem *d_display_picture_profile; - volatile void __iomem *d_display_luma_crc;/* v7 and v8 */ - volatile void __iomem *d_display_chroma0_crc;/* v7 and v8 */ - volatile void __iomem *d_display_chroma1_crc;/* only v8 */ - volatile void __iomem *d_display_luma_crc_top;/* only v6 */ - volatile void __iomem *d_display_chroma_crc_top;/* only v6 */ - volatile void __iomem *d_display_luma_crc_bot;/* only v6 */ - volatile void __iomem *d_display_chroma_crc_bot;/* only v6 */ - volatile void __iomem *d_display_aspect_ratio; - volatile void __iomem *d_display_extended_ar; - volatile void __iomem *d_decoded_frame_width; - volatile void __iomem *d_decoded_frame_height; - volatile void __iomem *d_decoded_status; - volatile void __iomem *d_decoded_first_plane_addr; - volatile void __iomem *d_decoded_second_plane_addr; - volatile void __iomem *d_decoded_third_plane_addr;/* only v8 */ - volatile void __iomem *d_decoded_frame_type; - volatile void __iomem *d_decoded_crop_info1; - volatile void __iomem *d_decoded_crop_info2; - volatile void __iomem *d_decoded_picture_profile; - volatile void __iomem *d_decoded_nal_size; - volatile void __iomem *d_decoded_luma_crc; - volatile void __iomem *d_decoded_chroma0_crc; - volatile void __iomem *d_decoded_chroma1_crc;/* only v8 */ - volatile void __iomem *d_ret_picture_tag_top; - volatile void __iomem *d_ret_picture_tag_bot; - volatile void __iomem *d_ret_picture_time_top; - volatile void __iomem *d_ret_picture_time_bot; - volatile void __iomem *d_chroma_format; - volatile void __iomem *d_vc1_info;/* v7 and v8 */ - volatile void __iomem *d_mpeg4_info; - volatile void __iomem *d_h264_info; - volatile void __iomem *d_metadata_addr_concealed_mb; - volatile void __iomem *d_metadata_size_concealed_mb; - volatile void __iomem *d_metadata_addr_vc1_param; - volatile void __iomem *d_metadata_size_vc1_param; - volatile void __iomem *d_metadata_addr_sei_nal; - volatile void __iomem *d_metadata_size_sei_nal; - volatile void __iomem *d_metadata_addr_vui; - volatile void __iomem *d_metadata_size_vui; - volatile void __iomem *d_metadata_addr_mvcvui;/* v7 and v8 */ - volatile void __iomem *d_metadata_size_mvcvui;/* v7 and v8 */ - volatile void __iomem *d_mvc_view_id; - volatile void __iomem *d_frame_pack_sei_avail; - volatile void __iomem *d_frame_pack_arrgment_id; - volatile void __iomem *d_frame_pack_sei_info; - volatile void __iomem *d_frame_pack_grid_pos; - volatile void __iomem *d_display_recovery_sei_info;/* v7 and v8 */ - volatile void __iomem *d_decoded_recovery_sei_info;/* v7 and v8 */ - volatile void __iomem *d_display_first_addr;/* only v7 */ - volatile void __iomem *d_display_second_addr;/* only v7 */ - volatile void __iomem *d_display_third_addr;/* only v7 */ - volatile void __iomem *d_decoded_first_addr;/* only v7 */ - volatile void __iomem *d_decoded_second_addr;/* only v7 */ - volatile void __iomem *d_decoded_third_addr;/* only v7 */ - volatile void __iomem *d_used_dpb_flag_upper;/* v7 and v8 */ - volatile void __iomem *d_used_dpb_flag_lower;/* v7 and v8 */ + void __iomem *d_crc_ctrl; + void __iomem *d_dec_options; + void __iomem *d_display_delay; + void __iomem *d_set_frame_width; + void __iomem *d_set_frame_height; + void __iomem *d_sei_enable; + void __iomem *d_min_num_dpb; + void __iomem *d_min_first_plane_dpb_size; + void __iomem *d_min_second_plane_dpb_size; + void __iomem *d_min_third_plane_dpb_size;/* only v8 */ + void __iomem *d_min_num_mv; + void __iomem *d_mvc_num_views; + void __iomem *d_min_num_dis;/* only v7 */ + void __iomem *d_min_first_dis_size;/* only v7 */ + void __iomem *d_min_second_dis_size;/* only v7 */ + void __iomem *d_min_third_dis_size;/* only v7 */ + void __iomem *d_post_filter_luma_dpb0;/* v7 and v8 */ + void __iomem *d_post_filter_luma_dpb1;/* v7 and v8 */ + void __iomem *d_post_filter_luma_dpb2;/* only v7 */ + void __iomem *d_post_filter_chroma_dpb0;/* v7 and v8 */ + void __iomem *d_post_filter_chroma_dpb1;/* v7 and v8 */ + void __iomem *d_post_filter_chroma_dpb2;/* only v7 */ + void __iomem *d_num_dpb; + void __iomem *d_num_mv; + void __iomem *d_init_buffer_options; + void __iomem *d_first_plane_dpb_stride_size;/* only v8 */ + void __iomem *d_second_plane_dpb_stride_size;/* only v8 */ + void __iomem *d_third_plane_dpb_stride_size;/* only v8 */ + void __iomem *d_first_plane_dpb_size; + void __iomem *d_second_plane_dpb_size; + void __iomem *d_third_plane_dpb_size;/* only v8 */ + void __iomem *d_mv_buffer_size; + void __iomem *d_first_plane_dpb; + void __iomem *d_second_plane_dpb; + void __iomem *d_third_plane_dpb; + void __iomem *d_mv_buffer; + void __iomem *d_scratch_buffer_addr; + void __iomem *d_scratch_buffer_size; + void __iomem *d_metadata_buffer_addr; + void __iomem *d_metadata_buffer_size; + void __iomem *d_nal_start_options;/* v7 and v8 */ + void __iomem *d_cpb_buffer_addr; + void __iomem *d_cpb_buffer_size; + void __iomem *d_available_dpb_flag_upper; + void __iomem *d_available_dpb_flag_lower; + void __iomem *d_cpb_buffer_offset; + void __iomem *d_slice_if_enable; + void __iomem *d_picture_tag; + void __iomem *d_stream_data_size; + void __iomem *d_dynamic_dpb_flag_upper;/* v7 and v8 */ + void __iomem *d_dynamic_dpb_flag_lower;/* v7 and v8 */ + void __iomem *d_display_frame_width; + void __iomem *d_display_frame_height; + void __iomem *d_display_status; + void __iomem *d_display_first_plane_addr; + void __iomem *d_display_second_plane_addr; + void __iomem *d_display_third_plane_addr;/* only v8 */ + void __iomem *d_display_frame_type; + void __iomem *d_display_crop_info1; + void __iomem *d_display_crop_info2; + void __iomem *d_display_picture_profile; + void __iomem *d_display_luma_crc;/* v7 and v8 */ + void __iomem *d_display_chroma0_crc;/* v7 and v8 */ + void __iomem *d_display_chroma1_crc;/* only v8 */ + void __iomem *d_display_luma_crc_top;/* only v6 */ + void __iomem *d_display_chroma_crc_top;/* only v6 */ + void __iomem *d_display_luma_crc_bot;/* only v6 */ + void __iomem *d_display_chroma_crc_bot;/* only v6 */ + void __iomem *d_display_aspect_ratio; + void __iomem *d_display_extended_ar; + void __iomem *d_decoded_frame_width; + void __iomem *d_decoded_frame_height; + void __iomem *d_decoded_status; + void __iomem *d_decoded_first_plane_addr; + void __iomem *d_decoded_second_plane_addr; + void __iomem *d_decoded_third_plane_addr;/* only v8 */ + void __iomem *d_decoded_frame_type; + void __iomem *d_decoded_crop_info1; + void __iomem *d_decoded_crop_info2; + void __iomem *d_decoded_picture_profile; + void __iomem *d_decoded_nal_size; + void __iomem *d_decoded_luma_crc; + void __iomem *d_decoded_chroma0_crc; + void __iomem *d_decoded_chroma1_crc;/* only v8 */ + void __iomem *d_ret_picture_tag_top; + void __iomem *d_ret_picture_tag_bot; + void __iomem *d_ret_picture_time_top; + void __iomem *d_ret_picture_time_bot; + void __iomem *d_chroma_format; + void __iomem *d_vc1_info;/* v7 and v8 */ + void __iomem *d_mpeg4_info; + void __iomem *d_h264_info; + void __iomem *d_metadata_addr_concealed_mb; + void __iomem *d_metadata_size_concealed_mb; + void __iomem *d_metadata_addr_vc1_param; + void __iomem *d_metadata_size_vc1_param; + void __iomem *d_metadata_addr_sei_nal; + void __iomem *d_metadata_size_sei_nal; + void __iomem *d_metadata_addr_vui; + void __iomem *d_metadata_size_vui; + void __iomem *d_metadata_addr_mvcvui;/* v7 and v8 */ + void __iomem *d_metadata_size_mvcvui;/* v7 and v8 */ + void __iomem *d_mvc_view_id; + void __iomem *d_frame_pack_sei_avail; + void __iomem *d_frame_pack_arrgment_id; + void __iomem *d_frame_pack_sei_info; + void __iomem *d_frame_pack_grid_pos; + void __iomem *d_display_recovery_sei_info;/* v7 and v8 */ + void __iomem *d_decoded_recovery_sei_info;/* v7 and v8 */ + void __iomem *d_display_first_addr;/* only v7 */ + void __iomem *d_display_second_addr;/* only v7 */ + void __iomem *d_display_third_addr;/* only v7 */ + void __iomem *d_decoded_first_addr;/* only v7 */ + void __iomem *d_decoded_second_addr;/* only v7 */ + void __iomem *d_decoded_third_addr;/* only v7 */ + void __iomem *d_used_dpb_flag_upper;/* v7 and v8 */ + void __iomem *d_used_dpb_flag_lower;/* v7 and v8 */ /* encoder registers */ - volatile void __iomem *e_frame_width; - volatile void __iomem *e_frame_height; - volatile void __iomem *e_cropped_frame_width; - volatile void __iomem *e_cropped_frame_height; - volatile void __iomem *e_frame_crop_offset; - volatile void __iomem *e_enc_options; - volatile void __iomem *e_picture_profile; - volatile void __iomem *e_vbv_buffer_size; - volatile void __iomem *e_vbv_init_delay; - volatile void __iomem *e_fixed_picture_qp; - volatile void __iomem *e_rc_config; - volatile void __iomem *e_rc_qp_bound; - volatile void __iomem *e_rc_qp_bound_pb;/* v7 and v8 */ - volatile void __iomem *e_rc_mode; - volatile void __iomem *e_mb_rc_config; - volatile void __iomem *e_padding_ctrl; - volatile void __iomem *e_air_threshold; - volatile void __iomem *e_mv_hor_range; - volatile void __iomem *e_mv_ver_range; - volatile void __iomem *e_num_dpb; - volatile void __iomem *e_luma_dpb; - volatile void __iomem *e_chroma_dpb; - volatile void __iomem *e_me_buffer; - volatile void __iomem *e_scratch_buffer_addr; - volatile void __iomem *e_scratch_buffer_size; - volatile void __iomem *e_tmv_buffer0; - volatile void __iomem *e_tmv_buffer1; - volatile void __iomem *e_ir_buffer_addr;/* v7 and v8 */ - volatile void __iomem *e_source_first_plane_addr; - volatile void __iomem *e_source_second_plane_addr; - volatile void __iomem *e_source_third_plane_addr;/* v7 and v8 */ - volatile void __iomem *e_source_first_plane_stride;/* v7 and v8 */ - volatile void __iomem *e_source_second_plane_stride;/* v7 and v8 */ - volatile void __iomem *e_source_third_plane_stride;/* v7 and v8 */ - volatile void __iomem *e_stream_buffer_addr; - volatile void __iomem *e_stream_buffer_size; - volatile void __iomem *e_roi_buffer_addr; - volatile void __iomem *e_param_change; - volatile void __iomem *e_ir_size; - volatile void __iomem *e_gop_config; - volatile void __iomem *e_mslice_mode; - volatile void __iomem *e_mslice_size_mb; - volatile void __iomem *e_mslice_size_bits; - volatile void __iomem *e_frame_insertion; - volatile void __iomem *e_rc_frame_rate; - volatile void __iomem *e_rc_bit_rate; - volatile void __iomem *e_rc_roi_ctrl; - volatile void __iomem *e_picture_tag; - volatile void __iomem *e_bit_count_enable; - volatile void __iomem *e_max_bit_count; - volatile void __iomem *e_min_bit_count; - volatile void __iomem *e_metadata_buffer_addr; - volatile void __iomem *e_metadata_buffer_size; - volatile void __iomem *e_encoded_source_first_plane_addr; - volatile void __iomem *e_encoded_source_second_plane_addr; - volatile void __iomem *e_encoded_source_third_plane_addr;/* v7 and v8 */ - volatile void __iomem *e_stream_size; - volatile void __iomem *e_slice_type; - volatile void __iomem *e_picture_count; - volatile void __iomem *e_ret_picture_tag; - volatile void __iomem *e_stream_buffer_write_pointer; /* only v6 */ - volatile void __iomem *e_recon_luma_dpb_addr; - volatile void __iomem *e_recon_chroma_dpb_addr; - volatile void __iomem *e_metadata_addr_enc_slice; - volatile void __iomem *e_metadata_size_enc_slice; - volatile void __iomem *e_mpeg4_options; - volatile void __iomem *e_mpeg4_hec_period; - volatile void __iomem *e_aspect_ratio; - volatile void __iomem *e_extended_sar; - volatile void __iomem *e_h264_options; - volatile void __iomem *e_h264_options_2;/* v7 and v8 */ - volatile void __iomem *e_h264_lf_alpha_offset; - volatile void __iomem *e_h264_lf_beta_offset; - volatile void __iomem *e_h264_i_period; - volatile void __iomem *e_h264_fmo_slice_grp_map_type; - volatile void __iomem *e_h264_fmo_num_slice_grp_minus1; - volatile void __iomem *e_h264_fmo_slice_grp_change_dir; - volatile void __iomem *e_h264_fmo_slice_grp_change_rate_minus1; - volatile void __iomem *e_h264_fmo_run_length_minus1_0; - volatile void __iomem *e_h264_aso_slice_order_0; - volatile void __iomem *e_h264_chroma_qp_offset; - volatile void __iomem *e_h264_num_t_layer; - volatile void __iomem *e_h264_hierarchical_qp_layer0; - volatile void __iomem *e_h264_frame_packing_sei_info; - volatile void __iomem *e_h264_nal_control;/* v7 and v8 */ - volatile void __iomem *e_mvc_frame_qp_view1; - volatile void __iomem *e_mvc_rc_bit_rate_view1; - volatile void __iomem *e_mvc_rc_qbound_view1; - volatile void __iomem *e_mvc_rc_mode_view1; - volatile void __iomem *e_mvc_inter_view_prediction_on; - volatile void __iomem *e_vp8_options;/* v7 and v8 */ - volatile void __iomem *e_vp8_filter_options;/* v7 and v8 */ - volatile void __iomem *e_vp8_golden_frame_option;/* v7 and v8 */ - volatile void __iomem *e_vp8_num_t_layer;/* v7 and v8 */ - volatile void __iomem *e_vp8_hierarchical_qp_layer0;/* v7 and v8 */ - volatile void __iomem *e_vp8_hierarchical_qp_layer1;/* v7 and v8 */ - volatile void __iomem *e_vp8_hierarchical_qp_layer2;/* v7 and v8 */ + void __iomem *e_frame_width; + void __iomem *e_frame_height; + void __iomem *e_cropped_frame_width; + void __iomem *e_cropped_frame_height; + void __iomem *e_frame_crop_offset; + void __iomem *e_enc_options; + void __iomem *e_picture_profile; + void __iomem *e_vbv_buffer_size; + void __iomem *e_vbv_init_delay; + void __iomem *e_fixed_picture_qp; + void __iomem *e_rc_config; + void __iomem *e_rc_qp_bound; + void __iomem *e_rc_qp_bound_pb;/* v7 and v8 */ + void __iomem *e_rc_mode; + void __iomem *e_mb_rc_config; + void __iomem *e_padding_ctrl; + void __iomem *e_air_threshold; + void __iomem *e_mv_hor_range; + void __iomem *e_mv_ver_range; + void __iomem *e_num_dpb; + void __iomem *e_luma_dpb; + void __iomem *e_chroma_dpb; + void __iomem *e_me_buffer; + void __iomem *e_scratch_buffer_addr; + void __iomem *e_scratch_buffer_size; + void __iomem *e_tmv_buffer0; + void __iomem *e_tmv_buffer1; + void __iomem *e_ir_buffer_addr;/* v7 and v8 */ + void __iomem *e_source_first_plane_addr; + void __iomem *e_source_second_plane_addr; + void __iomem *e_source_third_plane_addr;/* v7 and v8 */ + void __iomem *e_source_first_plane_stride;/* v7 and v8 */ + void __iomem *e_source_second_plane_stride;/* v7 and v8 */ + void __iomem *e_source_third_plane_stride;/* v7 and v8 */ + void __iomem *e_stream_buffer_addr; + void __iomem *e_stream_buffer_size; + void __iomem *e_roi_buffer_addr; + void __iomem *e_param_change; + void __iomem *e_ir_size; + void __iomem *e_gop_config; + void __iomem *e_mslice_mode; + void __iomem *e_mslice_size_mb; + void __iomem *e_mslice_size_bits; + void __iomem *e_frame_insertion; + void __iomem *e_rc_frame_rate; + void __iomem *e_rc_bit_rate; + void __iomem *e_rc_roi_ctrl; + void __iomem *e_picture_tag; + void __iomem *e_bit_count_enable; + void __iomem *e_max_bit_count; + void __iomem *e_min_bit_count; + void __iomem *e_metadata_buffer_addr; + void __iomem *e_metadata_buffer_size; + void __iomem *e_encoded_source_first_plane_addr; + void __iomem *e_encoded_source_second_plane_addr; + void __iomem *e_encoded_source_third_plane_addr;/* v7 and v8 */ + void __iomem *e_stream_size; + void __iomem *e_slice_type; + void __iomem *e_picture_count; + void __iomem *e_ret_picture_tag; + void __iomem *e_stream_buffer_write_pointer; /* only v6 */ + void __iomem *e_recon_luma_dpb_addr; + void __iomem *e_recon_chroma_dpb_addr; + void __iomem *e_metadata_addr_enc_slice; + void __iomem *e_metadata_size_enc_slice; + void __iomem *e_mpeg4_options; + void __iomem *e_mpeg4_hec_period; + void __iomem *e_aspect_ratio; + void __iomem *e_extended_sar; + void __iomem *e_h264_options; + void __iomem *e_h264_options_2;/* v7 and v8 */ + void __iomem *e_h264_lf_alpha_offset; + void __iomem *e_h264_lf_beta_offset; + void __iomem *e_h264_i_period; + void __iomem *e_h264_fmo_slice_grp_map_type; + void __iomem *e_h264_fmo_num_slice_grp_minus1; + void __iomem *e_h264_fmo_slice_grp_change_dir; + void __iomem *e_h264_fmo_slice_grp_change_rate_minus1; + void __iomem *e_h264_fmo_run_length_minus1_0; + void __iomem *e_h264_aso_slice_order_0; + void __iomem *e_h264_chroma_qp_offset; + void __iomem *e_h264_num_t_layer; + void __iomem *e_h264_hierarchical_qp_layer0; + void __iomem *e_h264_frame_packing_sei_info; + void __iomem *e_h264_nal_control;/* v7 and v8 */ + void __iomem *e_mvc_frame_qp_view1; + void __iomem *e_mvc_rc_bit_rate_view1; + void __iomem *e_mvc_rc_qbound_view1; + void __iomem *e_mvc_rc_mode_view1; + void __iomem *e_mvc_inter_view_prediction_on; + void __iomem *e_vp8_options;/* v7 and v8 */ + void __iomem *e_vp8_filter_options;/* v7 and v8 */ + void __iomem *e_vp8_golden_frame_option;/* v7 and v8 */ + void __iomem *e_vp8_num_t_layer;/* v7 and v8 */ + void __iomem *e_vp8_hierarchical_qp_layer0;/* v7 and v8 */ + void __iomem *e_vp8_hierarchical_qp_layer1;/* v7 and v8 */ + void __iomem *e_vp8_hierarchical_qp_layer2;/* v7 and v8 */ }; struct s5p_mfc_hw_ops { @@ -281,28 +281,14 @@ struct s5p_mfc_hw_ops { void (*release_dev_context_buffer)(struct s5p_mfc_dev *dev); void (*dec_calc_dpb_size)(struct s5p_mfc_ctx *ctx); void (*enc_calc_src_size)(struct s5p_mfc_ctx *ctx); - int (*set_dec_stream_buffer)(struct s5p_mfc_ctx *ctx, - int buf_addr, unsigned int start_num_byte, - unsigned int buf_size); - int (*set_dec_frame_buffer)(struct s5p_mfc_ctx *ctx); int (*set_enc_stream_buffer)(struct s5p_mfc_ctx *ctx, unsigned long addr, unsigned int size); void (*set_enc_frame_buffer)(struct s5p_mfc_ctx *ctx, unsigned long y_addr, unsigned long c_addr); void (*get_enc_frame_buffer)(struct s5p_mfc_ctx *ctx, unsigned long *y_addr, unsigned long *c_addr); - int (*set_enc_ref_buffer)(struct s5p_mfc_ctx *ctx); - int (*init_decode)(struct s5p_mfc_ctx *ctx); - int (*init_encode)(struct s5p_mfc_ctx *ctx); - int (*encode_one_frame)(struct s5p_mfc_ctx *ctx); void (*try_run)(struct s5p_mfc_dev *dev); - void (*cleanup_queue)(struct list_head *lh, - struct vb2_queue *vq); void (*clear_int_flags)(struct s5p_mfc_dev *dev); - void (*write_info)(struct s5p_mfc_ctx *ctx, unsigned int data, - unsigned int ofs); - unsigned int (*read_info)(struct s5p_mfc_ctx *ctx, - unsigned long ofs); int (*get_dspl_y_adr)(struct s5p_mfc_dev *dev); int (*get_dec_y_adr)(struct s5p_mfc_dev *dev); int (*get_dspl_status)(struct s5p_mfc_dev *dev); @@ -313,7 +299,6 @@ struct s5p_mfc_hw_ops { int (*get_int_reason)(struct s5p_mfc_dev *dev); int (*get_int_err)(struct s5p_mfc_dev *dev); int (*err_dec)(unsigned int err); - int (*err_dspl)(unsigned int err); int (*get_img_width)(struct s5p_mfc_dev *dev); int (*get_img_height)(struct s5p_mfc_dev *dev); int (*get_dpb_count)(struct s5p_mfc_dev *dev); @@ -322,10 +307,6 @@ struct s5p_mfc_hw_ops { int (*get_enc_strm_size)(struct s5p_mfc_dev *dev); int (*get_enc_slice_type)(struct s5p_mfc_dev *dev); int (*get_enc_dpb_count)(struct s5p_mfc_dev *dev); - int (*get_enc_pic_count)(struct s5p_mfc_dev *dev); - int (*get_sei_avail_status)(struct s5p_mfc_ctx *ctx); - int (*get_mvc_num_views)(struct s5p_mfc_dev *dev); - int (*get_mvc_view_id)(struct s5p_mfc_dev *dev); unsigned int (*get_pic_type_top)(struct s5p_mfc_ctx *ctx); unsigned int (*get_pic_type_bot)(struct s5p_mfc_ctx *ctx); unsigned int (*get_crop_info_h)(struct s5p_mfc_ctx *ctx); diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c index 873c933bc..81e1e4ce6 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c @@ -1153,27 +1153,6 @@ static int s5p_mfc_encode_one_frame_v5(struct s5p_mfc_ctx *ctx) return 0; } -static int s5p_mfc_get_new_ctx(struct s5p_mfc_dev *dev) -{ - unsigned long flags; - int new_ctx; - int cnt; - - spin_lock_irqsave(&dev->condlock, flags); - new_ctx = (dev->curr_ctx + 1) % MFC_NUM_CONTEXTS; - cnt = 0; - while (!test_bit(new_ctx, &dev->ctx_work_bits)) { - new_ctx = (new_ctx + 1) % MFC_NUM_CONTEXTS; - if (++cnt > MFC_NUM_CONTEXTS) { - /* No contexts to run */ - spin_unlock_irqrestore(&dev->condlock, flags); - return -EAGAIN; - } - } - spin_unlock_irqrestore(&dev->condlock, flags); - return new_ctx; -} - static void s5p_mfc_run_res_change(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; @@ -1187,7 +1166,6 @@ static int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx, int last_frame) { struct s5p_mfc_dev *dev = ctx->dev; struct s5p_mfc_buf *temp_vb; - unsigned long flags; if (ctx->state == MFCINST_FINISHING) { last_frame = MFC_DEC_LAST_FRAME; @@ -1197,11 +1175,9 @@ static int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx, int last_frame) return 0; } - spin_lock_irqsave(&dev->irqlock, flags); /* Frames are being decoded */ if (list_empty(&ctx->src_queue)) { mfc_debug(2, "No src buffers\n"); - spin_unlock_irqrestore(&dev->irqlock, flags); return -EAGAIN; } /* Get the next source buffer */ @@ -1210,7 +1186,6 @@ static int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx, int last_frame) s5p_mfc_set_dec_stream_buffer_v5(ctx, vb2_dma_contig_plane_dma_addr(&temp_vb->b->vb2_buf, 0), ctx->consumed_stream, temp_vb->b->vb2_buf.planes[0].bytesused); - spin_unlock_irqrestore(&dev->irqlock, flags); dev->curr_ctx = ctx->num; if (temp_vb->b->vb2_buf.planes[0].bytesused == 0) { last_frame = MFC_DEC_LAST_FRAME; @@ -1224,21 +1199,17 @@ static int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx, int last_frame) static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; - unsigned long flags; struct s5p_mfc_buf *dst_mb; struct s5p_mfc_buf *src_mb; unsigned long src_y_addr, src_c_addr, dst_addr; unsigned int dst_size; - spin_lock_irqsave(&dev->irqlock, flags); if (list_empty(&ctx->src_queue) && ctx->state != MFCINST_FINISHING) { mfc_debug(2, "no src buffers\n"); - spin_unlock_irqrestore(&dev->irqlock, flags); return -EAGAIN; } if (list_empty(&ctx->dst_queue)) { mfc_debug(2, "no dst buffers\n"); - spin_unlock_irqrestore(&dev->irqlock, flags); return -EAGAIN; } if (list_empty(&ctx->src_queue)) { @@ -1270,7 +1241,6 @@ static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx) dst_addr = vb2_dma_contig_plane_dma_addr(&dst_mb->b->vb2_buf, 0); dst_size = vb2_plane_size(&dst_mb->b->vb2_buf, 0); s5p_mfc_set_enc_stream_buffer_v5(ctx, dst_addr, dst_size); - spin_unlock_irqrestore(&dev->irqlock, flags); dev->curr_ctx = ctx->num; mfc_debug(2, "encoding buffer with index=%d state=%d\n", src_mb ? src_mb->b->vb2_buf.index : -1, ctx->state); @@ -1281,11 +1251,9 @@ static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx) static void s5p_mfc_run_init_dec(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; - unsigned long flags; struct s5p_mfc_buf *temp_vb; /* Initializing decoding - parsing header */ - spin_lock_irqsave(&dev->irqlock, flags); mfc_debug(2, "Preparing to init decoding\n"); temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); s5p_mfc_set_dec_desc_buffer(ctx); @@ -1294,7 +1262,6 @@ static void s5p_mfc_run_init_dec(struct s5p_mfc_ctx *ctx) s5p_mfc_set_dec_stream_buffer_v5(ctx, vb2_dma_contig_plane_dma_addr(&temp_vb->b->vb2_buf, 0), 0, temp_vb->b->vb2_buf.planes[0].bytesused); - spin_unlock_irqrestore(&dev->irqlock, flags); dev->curr_ctx = ctx->num; s5p_mfc_init_decode_v5(ctx); } @@ -1302,18 +1269,15 @@ static void s5p_mfc_run_init_dec(struct s5p_mfc_ctx *ctx) static void s5p_mfc_run_init_enc(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; - unsigned long flags; struct s5p_mfc_buf *dst_mb; unsigned long dst_addr; unsigned int dst_size; s5p_mfc_set_enc_ref_buffer_v5(ctx); - spin_lock_irqsave(&dev->irqlock, flags); dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); dst_addr = vb2_dma_contig_plane_dma_addr(&dst_mb->b->vb2_buf, 0); dst_size = vb2_plane_size(&dst_mb->b->vb2_buf, 0); s5p_mfc_set_enc_stream_buffer_v5(ctx, dst_addr, dst_size); - spin_unlock_irqrestore(&dev->irqlock, flags); dev->curr_ctx = ctx->num; s5p_mfc_init_encode_v5(ctx); } @@ -1321,7 +1285,6 @@ static void s5p_mfc_run_init_enc(struct s5p_mfc_ctx *ctx) static int s5p_mfc_run_init_dec_buffers(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; - unsigned long flags; struct s5p_mfc_buf *temp_vb; int ret; @@ -1335,11 +1298,9 @@ static int s5p_mfc_run_init_dec_buffers(struct s5p_mfc_ctx *ctx) "before starting processing\n"); return -EAGAIN; } - spin_lock_irqsave(&dev->irqlock, flags); if (list_empty(&ctx->src_queue)) { mfc_err("Header has been deallocated in the middle of" " initialization\n"); - spin_unlock_irqrestore(&dev->irqlock, flags); return -EIO; } temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); @@ -1348,7 +1309,6 @@ static int s5p_mfc_run_init_dec_buffers(struct s5p_mfc_ctx *ctx) s5p_mfc_set_dec_stream_buffer_v5(ctx, vb2_dma_contig_plane_dma_addr(&temp_vb->b->vb2_buf, 0), 0, temp_vb->b->vb2_buf.planes[0].bytesused); - spin_unlock_irqrestore(&dev->irqlock, flags); dev->curr_ctx = ctx->num; ret = s5p_mfc_set_dec_frame_buffer_v5(ctx); if (ret) { @@ -1472,21 +1432,6 @@ static void s5p_mfc_try_run_v5(struct s5p_mfc_dev *dev) } } - -static void s5p_mfc_cleanup_queue_v5(struct list_head *lh, struct vb2_queue *vq) -{ - struct s5p_mfc_buf *b; - int i; - - while (!list_empty(lh)) { - b = list_entry(lh->next, struct s5p_mfc_buf, list); - for (i = 0; i < b->b->vb2_buf.num_planes; i++) - vb2_set_plane_payload(&b->b->vb2_buf, i, 0); - vb2_buffer_done(&b->b->vb2_buf, VB2_BUF_STATE_ERROR); - list_del(&b->list); - } -} - static void s5p_mfc_clear_int_flags_v5(struct s5p_mfc_dev *dev) { mfc_write(dev, 0, S5P_FIMV_RISC_HOST_INT); @@ -1590,11 +1535,6 @@ static int s5p_mfc_err_dec_v5(unsigned int err) return (err & S5P_FIMV_ERR_DEC_MASK) >> S5P_FIMV_ERR_DEC_SHIFT; } -static int s5p_mfc_err_dspl_v5(unsigned int err) -{ - return (err & S5P_FIMV_ERR_DSPL_MASK) >> S5P_FIMV_ERR_DSPL_SHIFT; -} - static int s5p_mfc_get_img_width_v5(struct s5p_mfc_dev *dev) { return mfc_read(dev, S5P_FIMV_SI_HRESOL); @@ -1636,26 +1576,6 @@ static int s5p_mfc_get_enc_dpb_count_v5(struct s5p_mfc_dev *dev) return -1; } -static int s5p_mfc_get_enc_pic_count_v5(struct s5p_mfc_dev *dev) -{ - return mfc_read(dev, S5P_FIMV_ENC_SI_PIC_CNT); -} - -static int s5p_mfc_get_sei_avail_status_v5(struct s5p_mfc_ctx *ctx) -{ - return s5p_mfc_read_info_v5(ctx, FRAME_PACK_SEI_AVAIL); -} - -static int s5p_mfc_get_mvc_num_views_v5(struct s5p_mfc_dev *dev) -{ - return -1; -} - -static int s5p_mfc_get_mvc_view_id_v5(struct s5p_mfc_dev *dev) -{ - return -1; -} - static unsigned int s5p_mfc_get_pic_type_top_v5(struct s5p_mfc_ctx *ctx) { return s5p_mfc_read_info_v5(ctx, PIC_TIME_TOP); @@ -1688,20 +1608,11 @@ static struct s5p_mfc_hw_ops s5p_mfc_ops_v5 = { .release_dev_context_buffer = s5p_mfc_release_dev_context_buffer_v5, .dec_calc_dpb_size = s5p_mfc_dec_calc_dpb_size_v5, .enc_calc_src_size = s5p_mfc_enc_calc_src_size_v5, - .set_dec_stream_buffer = s5p_mfc_set_dec_stream_buffer_v5, - .set_dec_frame_buffer = s5p_mfc_set_dec_frame_buffer_v5, .set_enc_stream_buffer = s5p_mfc_set_enc_stream_buffer_v5, .set_enc_frame_buffer = s5p_mfc_set_enc_frame_buffer_v5, .get_enc_frame_buffer = s5p_mfc_get_enc_frame_buffer_v5, - .set_enc_ref_buffer = s5p_mfc_set_enc_ref_buffer_v5, - .init_decode = s5p_mfc_init_decode_v5, - .init_encode = s5p_mfc_init_encode_v5, - .encode_one_frame = s5p_mfc_encode_one_frame_v5, .try_run = s5p_mfc_try_run_v5, - .cleanup_queue = s5p_mfc_cleanup_queue_v5, .clear_int_flags = s5p_mfc_clear_int_flags_v5, - .write_info = s5p_mfc_write_info_v5, - .read_info = s5p_mfc_read_info_v5, .get_dspl_y_adr = s5p_mfc_get_dspl_y_adr_v5, .get_dec_y_adr = s5p_mfc_get_dec_y_adr_v5, .get_dspl_status = s5p_mfc_get_dspl_status_v5, @@ -1712,7 +1623,6 @@ static struct s5p_mfc_hw_ops s5p_mfc_ops_v5 = { .get_int_reason = s5p_mfc_get_int_reason_v5, .get_int_err = s5p_mfc_get_int_err_v5, .err_dec = s5p_mfc_err_dec_v5, - .err_dspl = s5p_mfc_err_dspl_v5, .get_img_width = s5p_mfc_get_img_width_v5, .get_img_height = s5p_mfc_get_img_height_v5, .get_dpb_count = s5p_mfc_get_dpb_count_v5, @@ -1721,10 +1631,6 @@ static struct s5p_mfc_hw_ops s5p_mfc_ops_v5 = { .get_enc_strm_size = s5p_mfc_get_enc_strm_size_v5, .get_enc_slice_type = s5p_mfc_get_enc_slice_type_v5, .get_enc_dpb_count = s5p_mfc_get_enc_dpb_count_v5, - .get_enc_pic_count = s5p_mfc_get_enc_pic_count_v5, - .get_sei_avail_status = s5p_mfc_get_sei_avail_status_v5, - .get_mvc_num_views = s5p_mfc_get_mvc_num_views_v5, - .get_mvc_view_id = s5p_mfc_get_mvc_view_id_v5, .get_pic_type_top = s5p_mfc_get_pic_type_top_v5, .get_pic_type_bot = s5p_mfc_get_pic_type_bot_v5, .get_crop_info_h = s5p_mfc_get_crop_info_h_v5, diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c index b95845347..d6f207e85 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c @@ -505,7 +505,7 @@ static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx) } writel(ctx->inst_no, mfc_regs->instance_id); - s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev, + s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, S5P_FIMV_CH_INIT_BUFS_V6, NULL); mfc_debug(2, "After setting buffers.\n"); @@ -603,7 +603,7 @@ static int s5p_mfc_set_enc_ref_buffer_v6(struct s5p_mfc_ctx *ctx) } writel(ctx->inst_no, mfc_regs->instance_id); - s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev, + s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, S5P_FIMV_CH_INIT_BUFS_V6, NULL); mfc_debug_leave(); @@ -1378,7 +1378,7 @@ static int s5p_mfc_init_decode_v6(struct s5p_mfc_ctx *ctx) writel(ctx->sei_fp_parse & 0x1, mfc_regs->d_sei_enable); writel(ctx->inst_no, mfc_regs->instance_id); - s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev, + s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, S5P_FIMV_CH_SEQ_HEADER_V6, NULL); mfc_debug_leave(); @@ -1393,7 +1393,7 @@ static inline void s5p_mfc_set_flush(struct s5p_mfc_ctx *ctx, int flush) if (flush) { dev->curr_ctx = ctx->num; writel(ctx->inst_no, mfc_regs->instance_id); - s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev, + s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, S5P_FIMV_H2R_CMD_FLUSH_V6, NULL); } } @@ -1413,11 +1413,11 @@ static int s5p_mfc_decode_one_frame_v6(struct s5p_mfc_ctx *ctx, * is the last frame or not. */ switch (last_frame) { case 0: - s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev, + s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, S5P_FIMV_CH_FRAME_START_V6, NULL); break; case 1: - s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev, + s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, S5P_FIMV_CH_LAST_FRAME_V6, NULL); break; default: @@ -1455,7 +1455,7 @@ static int s5p_mfc_init_encode_v6(struct s5p_mfc_ctx *ctx) } writel(ctx->inst_no, mfc_regs->instance_id); - s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev, + s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, S5P_FIMV_CH_SEQ_HEADER_V6, NULL); return 0; @@ -1500,37 +1500,13 @@ static int s5p_mfc_encode_one_frame_v6(struct s5p_mfc_ctx *ctx) cmd = S5P_FIMV_CH_LAST_FRAME_V6; writel(ctx->inst_no, mfc_regs->instance_id); - s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev, cmd, NULL); + s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, cmd, NULL); mfc_debug(2, "--\n"); return 0; } -static inline int s5p_mfc_get_new_ctx(struct s5p_mfc_dev *dev) -{ - unsigned long flags; - int new_ctx; - int cnt; - - spin_lock_irqsave(&dev->condlock, flags); - mfc_debug(2, "Previous context: %d (bits %08lx)\n", dev->curr_ctx, - dev->ctx_work_bits); - new_ctx = (dev->curr_ctx + 1) % MFC_NUM_CONTEXTS; - cnt = 0; - while (!test_bit(new_ctx, &dev->ctx_work_bits)) { - new_ctx = (new_ctx + 1) % MFC_NUM_CONTEXTS; - cnt++; - if (cnt > MFC_NUM_CONTEXTS) { - /* No contexts to run */ - spin_unlock_irqrestore(&dev->condlock, flags); - return -EAGAIN; - } - } - spin_unlock_irqrestore(&dev->condlock, flags); - return new_ctx; -} - static inline void s5p_mfc_run_dec_last_frames(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; @@ -1544,7 +1520,6 @@ static inline int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; struct s5p_mfc_buf *temp_vb; - unsigned long flags; int last_frame = 0; if (ctx->state == MFCINST_FINISHING) { @@ -1556,11 +1531,9 @@ static inline int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx) return 0; } - spin_lock_irqsave(&dev->irqlock, flags); /* Frames are being decoded */ if (list_empty(&ctx->src_queue)) { mfc_debug(2, "No src buffers.\n"); - spin_unlock_irqrestore(&dev->irqlock, flags); return -EAGAIN; } /* Get the next source buffer */ @@ -1570,7 +1543,6 @@ static inline int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx) vb2_dma_contig_plane_dma_addr(&temp_vb->b->vb2_buf, 0), ctx->consumed_stream, temp_vb->b->vb2_buf.planes[0].bytesused); - spin_unlock_irqrestore(&dev->irqlock, flags); dev->curr_ctx = ctx->num; if (temp_vb->b->vb2_buf.planes[0].bytesused == 0) { @@ -1586,7 +1558,6 @@ static inline int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx) static inline int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; - unsigned long flags; struct s5p_mfc_buf *dst_mb; struct s5p_mfc_buf *src_mb; unsigned long src_y_addr, src_c_addr, dst_addr; @@ -1595,17 +1566,13 @@ static inline int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx) */ unsigned int dst_size; - spin_lock_irqsave(&dev->irqlock, flags); - if (list_empty(&ctx->src_queue) && ctx->state != MFCINST_FINISHING) { mfc_debug(2, "no src buffers.\n"); - spin_unlock_irqrestore(&dev->irqlock, flags); return -EAGAIN; } if (list_empty(&ctx->dst_queue)) { mfc_debug(2, "no dst buffers.\n"); - spin_unlock_irqrestore(&dev->irqlock, flags); return -EAGAIN; } @@ -1639,8 +1606,6 @@ static inline int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx) s5p_mfc_set_enc_stream_buffer_v6(ctx, dst_addr, dst_size); - spin_unlock_irqrestore(&dev->irqlock, flags); - dev->curr_ctx = ctx->num; s5p_mfc_encode_one_frame_v6(ctx); @@ -1650,18 +1615,15 @@ static inline int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx) static inline void s5p_mfc_run_init_dec(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; - unsigned long flags; struct s5p_mfc_buf *temp_vb; /* Initializing decoding - parsing header */ - spin_lock_irqsave(&dev->irqlock, flags); mfc_debug(2, "Preparing to init decoding.\n"); temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); mfc_debug(2, "Header size: %d\n", temp_vb->b->vb2_buf.planes[0].bytesused); s5p_mfc_set_dec_stream_buffer_v6(ctx, vb2_dma_contig_plane_dma_addr(&temp_vb->b->vb2_buf, 0), 0, temp_vb->b->vb2_buf.planes[0].bytesused); - spin_unlock_irqrestore(&dev->irqlock, flags); dev->curr_ctx = ctx->num; s5p_mfc_init_decode_v6(ctx); } @@ -1669,18 +1631,14 @@ static inline void s5p_mfc_run_init_dec(struct s5p_mfc_ctx *ctx) static inline void s5p_mfc_run_init_enc(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; - unsigned long flags; struct s5p_mfc_buf *dst_mb; unsigned long dst_addr; unsigned int dst_size; - spin_lock_irqsave(&dev->irqlock, flags); - dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); dst_addr = vb2_dma_contig_plane_dma_addr(&dst_mb->b->vb2_buf, 0); dst_size = vb2_plane_size(&dst_mb->b->vb2_buf, 0); s5p_mfc_set_enc_stream_buffer_v6(ctx, dst_addr, dst_size); - spin_unlock_irqrestore(&dev->irqlock, flags); dev->curr_ctx = ctx->num; s5p_mfc_init_encode_v6(ctx); } @@ -1846,21 +1804,6 @@ static void s5p_mfc_try_run_v6(struct s5p_mfc_dev *dev) } } - -static void s5p_mfc_cleanup_queue_v6(struct list_head *lh, struct vb2_queue *vq) -{ - struct s5p_mfc_buf *b; - int i; - - while (!list_empty(lh)) { - b = list_entry(lh->next, struct s5p_mfc_buf, list); - for (i = 0; i < b->b->vb2_buf.num_planes; i++) - vb2_set_plane_payload(&b->b->vb2_buf, i, 0); - vb2_buffer_done(&b->b->vb2_buf, VB2_BUF_STATE_ERROR); - list_del(&b->list); - } -} - static void s5p_mfc_clear_int_flags_v6(struct s5p_mfc_dev *dev) { const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; @@ -1868,14 +1811,6 @@ static void s5p_mfc_clear_int_flags_v6(struct s5p_mfc_dev *dev) writel(0, mfc_regs->risc2host_int); } -static void s5p_mfc_write_info_v6(struct s5p_mfc_ctx *ctx, unsigned int data, - unsigned int ofs) -{ - s5p_mfc_clock_on(); - writel(data, (void __iomem *)((unsigned long)ofs)); - s5p_mfc_clock_off(); -} - static unsigned int s5p_mfc_read_info_v6(struct s5p_mfc_ctx *ctx, unsigned long ofs) { @@ -1942,11 +1877,6 @@ static int s5p_mfc_err_dec_v6(unsigned int err) return (err & S5P_FIMV_ERR_DEC_MASK_V6) >> S5P_FIMV_ERR_DEC_SHIFT_V6; } -static int s5p_mfc_err_dspl_v6(unsigned int err) -{ - return (err & S5P_FIMV_ERR_DSPL_MASK_V6) >> S5P_FIMV_ERR_DSPL_SHIFT_V6; -} - static int s5p_mfc_get_img_width_v6(struct s5p_mfc_dev *dev) { return readl(dev->mfc_regs->d_display_frame_width); @@ -1987,27 +1917,6 @@ static int s5p_mfc_get_enc_slice_type_v6(struct s5p_mfc_dev *dev) return readl(dev->mfc_regs->e_slice_type); } -static int s5p_mfc_get_enc_pic_count_v6(struct s5p_mfc_dev *dev) -{ - return readl(dev->mfc_regs->e_picture_count); -} - -static int s5p_mfc_get_sei_avail_status_v6(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - return readl(dev->mfc_regs->d_frame_pack_sei_avail); -} - -static int s5p_mfc_get_mvc_num_views_v6(struct s5p_mfc_dev *dev) -{ - return readl(dev->mfc_regs->d_mvc_num_views); -} - -static int s5p_mfc_get_mvc_view_id_v6(struct s5p_mfc_dev *dev) -{ - return readl(dev->mfc_regs->d_mvc_view_id); -} - static unsigned int s5p_mfc_get_pic_type_top_v6(struct s5p_mfc_ctx *ctx) { return s5p_mfc_read_info_v6(ctx, @@ -2282,20 +2191,11 @@ static struct s5p_mfc_hw_ops s5p_mfc_ops_v6 = { s5p_mfc_release_dev_context_buffer_v6, .dec_calc_dpb_size = s5p_mfc_dec_calc_dpb_size_v6, .enc_calc_src_size = s5p_mfc_enc_calc_src_size_v6, - .set_dec_stream_buffer = s5p_mfc_set_dec_stream_buffer_v6, - .set_dec_frame_buffer = s5p_mfc_set_dec_frame_buffer_v6, .set_enc_stream_buffer = s5p_mfc_set_enc_stream_buffer_v6, .set_enc_frame_buffer = s5p_mfc_set_enc_frame_buffer_v6, .get_enc_frame_buffer = s5p_mfc_get_enc_frame_buffer_v6, - .set_enc_ref_buffer = s5p_mfc_set_enc_ref_buffer_v6, - .init_decode = s5p_mfc_init_decode_v6, - .init_encode = s5p_mfc_init_encode_v6, - .encode_one_frame = s5p_mfc_encode_one_frame_v6, .try_run = s5p_mfc_try_run_v6, - .cleanup_queue = s5p_mfc_cleanup_queue_v6, .clear_int_flags = s5p_mfc_clear_int_flags_v6, - .write_info = s5p_mfc_write_info_v6, - .read_info = s5p_mfc_read_info_v6, .get_dspl_y_adr = s5p_mfc_get_dspl_y_adr_v6, .get_dec_y_adr = s5p_mfc_get_dec_y_adr_v6, .get_dspl_status = s5p_mfc_get_dspl_status_v6, @@ -2306,7 +2206,6 @@ static struct s5p_mfc_hw_ops s5p_mfc_ops_v6 = { .get_int_reason = s5p_mfc_get_int_reason_v6, .get_int_err = s5p_mfc_get_int_err_v6, .err_dec = s5p_mfc_err_dec_v6, - .err_dspl = s5p_mfc_err_dspl_v6, .get_img_width = s5p_mfc_get_img_width_v6, .get_img_height = s5p_mfc_get_img_height_v6, .get_dpb_count = s5p_mfc_get_dpb_count_v6, @@ -2315,10 +2214,6 @@ static struct s5p_mfc_hw_ops s5p_mfc_ops_v6 = { .get_enc_strm_size = s5p_mfc_get_enc_strm_size_v6, .get_enc_slice_type = s5p_mfc_get_enc_slice_type_v6, .get_enc_dpb_count = s5p_mfc_get_enc_dpb_count_v6, - .get_enc_pic_count = s5p_mfc_get_enc_pic_count_v6, - .get_sei_avail_status = s5p_mfc_get_sei_avail_status_v6, - .get_mvc_num_views = s5p_mfc_get_mvc_num_views_v6, - .get_mvc_view_id = s5p_mfc_get_mvc_view_id_v6, .get_pic_type_top = s5p_mfc_get_pic_type_top_v6, .get_pic_type_bot = s5p_mfc_get_pic_type_bot_v6, .get_crop_info_h = s5p_mfc_get_crop_info_h_v6, diff --git a/drivers/media/platform/s5p-tv/hdmi_drv.c b/drivers/media/platform/s5p-tv/hdmi_drv.c index 79940757b..e71b13e40 100644 --- a/drivers/media/platform/s5p-tv/hdmi_drv.c +++ b/drivers/media/platform/s5p-tv/hdmi_drv.c @@ -33,7 +33,7 @@ #include <linux/regulator/consumer.h> #include <linux/v4l2-dv-timings.h> -#include <media/s5p_hdmi.h> +#include <linux/platform_data/media/s5p_hdmi.h> #include <media/v4l2-common.h> #include <media/v4l2-dev.h> #include <media/v4l2-device.h> @@ -627,7 +627,7 @@ static int hdmi_s_dv_timings(struct v4l2_subdev *sd, for (i = 0; i < ARRAY_SIZE(hdmi_timings); i++) if (v4l2_match_dv_timings(&hdmi_timings[i].dv_timings, - timings, 0)) + timings, 0, false)) break; if (i == ARRAY_SIZE(hdmi_timings)) { dev_err(dev, "timings not supported\n"); diff --git a/drivers/media/platform/s5p-tv/mixer_video.c b/drivers/media/platform/s5p-tv/mixer_video.c index dc1c679e1..d9e7f0302 100644 --- a/drivers/media/platform/s5p-tv/mixer_video.c +++ b/drivers/media/platform/s5p-tv/mixer_video.c @@ -881,7 +881,7 @@ static const struct v4l2_file_operations mxr_fops = { .unlocked_ioctl = video_ioctl2, }; -static int queue_setup(struct vb2_queue *vq, const void *parg, +static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) { diff --git a/drivers/media/platform/s5p-tv/sii9234_drv.c b/drivers/media/platform/s5p-tv/sii9234_drv.c index 8d171310a..0a97f9ab4 100644 --- a/drivers/media/platform/s5p-tv/sii9234_drv.c +++ b/drivers/media/platform/s5p-tv/sii9234_drv.c @@ -23,7 +23,7 @@ #include <linux/regulator/machine.h> #include <linux/slab.h> -#include <media/sii9234.h> +#include <linux/platform_data/media/sii9234.h> #include <media/v4l2-subdev.h> MODULE_AUTHOR("Tomasz Stanislawski <t.stanislaws@samsung.com>"); diff --git a/drivers/media/platform/sh_veu.c b/drivers/media/platform/sh_veu.c index d6ab33e70..82b5d69b8 100644 --- a/drivers/media/platform/sh_veu.c +++ b/drivers/media/platform/sh_veu.c @@ -865,32 +865,14 @@ static const struct v4l2_ioctl_ops sh_veu_ioctl_ops = { /* ========== Queue operations ========== */ static int sh_veu_queue_setup(struct vb2_queue *vq, - const void *parg, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) { - const struct v4l2_format *f = parg; struct sh_veu_dev *veu = vb2_get_drv_priv(vq); - struct sh_veu_vfmt *vfmt; - unsigned int size, count = *nbuffers; - - if (f) { - const struct v4l2_pix_format *pix = &f->fmt.pix; - const struct sh_veu_format *fmt = sh_veu_find_fmt(f); - struct v4l2_format ftmp = *f; - - if (fmt->fourcc != pix->pixelformat) - return -EINVAL; - sh_veu_try_fmt(&ftmp, fmt); - if (ftmp.fmt.pix.width != pix->width || - ftmp.fmt.pix.height != pix->height) - return -EINVAL; - size = pix->bytesperline ? pix->bytesperline * pix->height * fmt->depth / fmt->ydepth : - pix->width * pix->height * fmt->depth / fmt->ydepth; - } else { - vfmt = sh_veu_get_vfmt(veu, vq->type); - size = vfmt->bytesperline * vfmt->frame.height * vfmt->fmt->depth / vfmt->fmt->ydepth; - } + struct sh_veu_vfmt *vfmt = sh_veu_get_vfmt(veu, vq->type); + unsigned int count = *nbuffers; + unsigned int size = vfmt->bytesperline * vfmt->frame.height * + vfmt->fmt->depth / vfmt->fmt->ydepth; if (count < 2) *nbuffers = count = 2; @@ -900,6 +882,11 @@ static int sh_veu_queue_setup(struct vb2_queue *vq, *nbuffers = count; } + if (*nplanes) { + alloc_ctxs[0] = veu->alloc_ctx; + return sizes[0] < size ? -EINVAL : 0; + } + *nplanes = 1; sizes[0] = size; alloc_ctxs[0] = veu->alloc_ctx; @@ -1107,7 +1094,7 @@ static irqreturn_t sh_veu_isr(int irq, void *dev_id) if (!src || !dst) return IRQ_NONE; - dst->timestamp = src->timestamp; + dst->vb2_buf.timestamp = src->vb2_buf.timestamp; dst->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; dst->flags |= src->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK; diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c index 2231f8922..115740498 100644 --- a/drivers/media/platform/sh_vou.c +++ b/drivers/media/platform/sh_vou.c @@ -22,7 +22,7 @@ #include <linux/videodev2.h> #include <linux/module.h> -#include <media/sh_vou.h> +#include <media/drv-intf/sh_vou.h> #include <media/v4l2-common.h> #include <media/v4l2-device.h> #include <media/v4l2-ioctl.h> @@ -243,22 +243,21 @@ static void sh_vou_stream_config(struct sh_vou_device *vou_dev) } /* Locking: caller holds fop_lock mutex */ -static int sh_vou_queue_setup(struct vb2_queue *vq, const void *parg, +static int sh_vou_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) { - const struct v4l2_format *fmt = parg; struct sh_vou_device *vou_dev = vb2_get_drv_priv(vq); struct v4l2_pix_format *pix = &vou_dev->pix; int bytes_per_line = vou_fmt[vou_dev->pix_idx].bpp * pix->width / 8; dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); - if (fmt && fmt->fmt.pix.sizeimage < pix->height * bytes_per_line) - return -EINVAL; - *nplanes = 1; - sizes[0] = fmt ? fmt->fmt.pix.sizeimage : pix->height * bytes_per_line; alloc_ctxs[0] = vou_dev->alloc_ctx; + if (*nplanes) + return sizes[0] < pix->height * bytes_per_line ? -EINVAL : 0; + *nplanes = 1; + sizes[0] = pix->height * bytes_per_line; return 0; } @@ -1071,7 +1070,7 @@ static irqreturn_t sh_vou_isr(int irq, void *dev_id) list_del(&vb->list); - v4l2_get_timestamp(&vb->vb.timestamp); + vb->vb.vb2_buf.timestamp = ktime_get_ns(); vb->vb.sequence = vou_dev->sequence++; vb->vb.field = V4L2_FIELD_INTERLACED; vb2_buffer_done(&vb->vb.vb2_buf, VB2_BUF_STATE_DONE); diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index 454f68f0c..1af779ee3 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -24,7 +24,7 @@ #include <linux/slab.h> #include <media/soc_camera.h> -#include <media/soc_mediabus.h> +#include <media/drv-intf/soc_mediabus.h> #include <media/v4l2-of.h> #include <media/videobuf2-dma-contig.h> @@ -79,6 +79,7 @@ struct atmel_isi { dma_addr_t fb_descriptors_phys; struct list_head dma_desc_head; struct isi_dma_desc dma_desc[MAX_BUFFER_NUM]; + bool enable_preview_path; struct completion complete; /* ISI peripherial clock */ @@ -103,13 +104,55 @@ static u32 isi_readl(struct atmel_isi *isi, u32 reg) return readl(isi->regs + reg); } +static u32 setup_cfg2_yuv_swap(struct atmel_isi *isi, + const struct soc_camera_format_xlate *xlate) +{ + if (xlate->host_fmt->fourcc == V4L2_PIX_FMT_YUYV) { + /* all convert to YUYV */ + switch (xlate->code) { + case MEDIA_BUS_FMT_VYUY8_2X8: + return ISI_CFG2_YCC_SWAP_MODE_3; + case MEDIA_BUS_FMT_UYVY8_2X8: + return ISI_CFG2_YCC_SWAP_MODE_2; + case MEDIA_BUS_FMT_YVYU8_2X8: + return ISI_CFG2_YCC_SWAP_MODE_1; + } + } else if (xlate->host_fmt->fourcc == V4L2_PIX_FMT_RGB565) { + /* + * Preview path is enabled, it will convert UYVY to RGB format. + * But if sensor output format is not UYVY, we need to set + * YCC_SWAP_MODE to convert it as UYVY. + */ + switch (xlate->code) { + case MEDIA_BUS_FMT_VYUY8_2X8: + return ISI_CFG2_YCC_SWAP_MODE_1; + case MEDIA_BUS_FMT_YUYV8_2X8: + return ISI_CFG2_YCC_SWAP_MODE_2; + case MEDIA_BUS_FMT_YVYU8_2X8: + return ISI_CFG2_YCC_SWAP_MODE_3; + } + } + + /* + * By default, no swap for the codec path of Atmel ISI. So codec + * output is same as sensor's output. + * For instance, if sensor's output is YUYV, then codec outputs YUYV. + * And if sensor's output is UYVY, then codec outputs UYVY. + */ + return ISI_CFG2_YCC_SWAP_DEFAULT; +} + static void configure_geometry(struct atmel_isi *isi, u32 width, - u32 height, u32 code) + u32 height, const struct soc_camera_format_xlate *xlate) { - u32 cfg2; + u32 cfg2, psize; + u32 fourcc = xlate->host_fmt->fourcc; + + isi->enable_preview_path = fourcc == V4L2_PIX_FMT_RGB565 || + fourcc == V4L2_PIX_FMT_RGB32; /* According to sensor's output format to set cfg2 */ - switch (code) { + switch (xlate->code) { default: /* Grey */ case MEDIA_BUS_FMT_Y8_1X8: @@ -117,16 +160,11 @@ static void configure_geometry(struct atmel_isi *isi, u32 width, break; /* YUV */ case MEDIA_BUS_FMT_VYUY8_2X8: - cfg2 = ISI_CFG2_YCC_SWAP_MODE_3 | ISI_CFG2_COL_SPACE_YCbCr; - break; case MEDIA_BUS_FMT_UYVY8_2X8: - cfg2 = ISI_CFG2_YCC_SWAP_MODE_2 | ISI_CFG2_COL_SPACE_YCbCr; - break; case MEDIA_BUS_FMT_YVYU8_2X8: - cfg2 = ISI_CFG2_YCC_SWAP_MODE_1 | ISI_CFG2_COL_SPACE_YCbCr; - break; case MEDIA_BUS_FMT_YUYV8_2X8: - cfg2 = ISI_CFG2_YCC_SWAP_DEFAULT | ISI_CFG2_COL_SPACE_YCbCr; + cfg2 = ISI_CFG2_COL_SPACE_YCbCr | + setup_cfg2_yuv_swap(isi, xlate); break; /* RGB, TODO */ } @@ -139,6 +177,16 @@ static void configure_geometry(struct atmel_isi *isi, u32 width, cfg2 |= ((height - 1) << ISI_CFG2_IM_VSIZE_OFFSET) & ISI_CFG2_IM_VSIZE_MASK; isi_writel(isi, ISI_CFG2, cfg2); + + /* No down sampling, preview size equal to sensor output size */ + psize = ((width - 1) << ISI_PSIZE_PREV_HSIZE_OFFSET) & + ISI_PSIZE_PREV_HSIZE_MASK; + psize |= ((height - 1) << ISI_PSIZE_PREV_VSIZE_OFFSET) & + ISI_PSIZE_PREV_VSIZE_MASK; + isi_writel(isi, ISI_PSIZE, psize); + isi_writel(isi, ISI_PDECF, ISI_PDECF_NO_SAMPLING); + + return; } static bool is_supported(struct soc_camera_device *icd, @@ -151,8 +199,9 @@ static bool is_supported(struct soc_camera_device *icd, case V4L2_PIX_FMT_UYVY: case V4L2_PIX_FMT_YVYU: case V4L2_PIX_FMT_VYUY: + /* RGB */ + case V4L2_PIX_FMT_RGB565: return true; - /* RGB, TODO */ default: return false; } @@ -165,7 +214,7 @@ static irqreturn_t atmel_isi_handle_streaming(struct atmel_isi *isi) struct frame_buffer *buf = isi->active; list_del_init(&buf->list); - v4l2_get_timestamp(&vbuf->timestamp); + vbuf->vb2_buf.timestamp = ktime_get_ns(); vbuf->sequence = isi->sequence++; vb2_buffer_done(&vbuf->vb2_buf, VB2_BUF_STATE_DONE); } @@ -176,11 +225,19 @@ static irqreturn_t atmel_isi_handle_streaming(struct atmel_isi *isi) /* start next dma frame. */ isi->active = list_entry(isi->video_buffer_list.next, struct frame_buffer, list); - isi_writel(isi, ISI_DMA_C_DSCR, - (u32)isi->active->p_dma_desc->fbd_phys); - isi_writel(isi, ISI_DMA_C_CTRL, - ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE); - isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH); + if (!isi->enable_preview_path) { + isi_writel(isi, ISI_DMA_C_DSCR, + (u32)isi->active->p_dma_desc->fbd_phys); + isi_writel(isi, ISI_DMA_C_CTRL, + ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE); + isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH); + } else { + isi_writel(isi, ISI_DMA_P_DSCR, + (u32)isi->active->p_dma_desc->fbd_phys); + isi_writel(isi, ISI_DMA_P_CTRL, + ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE); + isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_P_CH); + } } return IRQ_HANDLED; } @@ -207,7 +264,8 @@ static irqreturn_t isi_interrupt(int irq, void *dev_id) isi_writel(isi, ISI_INTDIS, ISI_CTRL_DIS); ret = IRQ_HANDLED; } else { - if (likely(pending & ISI_SR_CXFR_DONE)) + if (likely(pending & ISI_SR_CXFR_DONE) || + likely(pending & ISI_SR_PXFR_DONE)) ret = atmel_isi_handle_streaming(isi); } @@ -245,7 +303,7 @@ static int atmel_isi_wait_status(struct atmel_isi *isi, int wait_reset) /* ------------------------------------------------------------------ Videobuf operations ------------------------------------------------------------------*/ -static int queue_setup(struct vb2_queue *vq, const void *parg, +static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) { @@ -352,21 +410,35 @@ static void start_dma(struct atmel_isi *isi, struct frame_buffer *buffer) ISI_SR_CXFR_DONE | ISI_SR_PXFR_DONE); /* Check if already in a frame */ - if (isi_readl(isi, ISI_STATUS) & ISI_CTRL_CDC) { - dev_err(isi->soc_host.icd->parent, "Already in frame handling.\n"); - return; - } + if (!isi->enable_preview_path) { + if (isi_readl(isi, ISI_STATUS) & ISI_CTRL_CDC) { + dev_err(isi->soc_host.icd->parent, "Already in frame handling.\n"); + return; + } - isi_writel(isi, ISI_DMA_C_DSCR, (u32)buffer->p_dma_desc->fbd_phys); - isi_writel(isi, ISI_DMA_C_CTRL, ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE); - isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH); + isi_writel(isi, ISI_DMA_C_DSCR, + (u32)buffer->p_dma_desc->fbd_phys); + isi_writel(isi, ISI_DMA_C_CTRL, + ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE); + isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH); + } else { + isi_writel(isi, ISI_DMA_P_DSCR, + (u32)buffer->p_dma_desc->fbd_phys); + isi_writel(isi, ISI_DMA_P_CTRL, + ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE); + isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_P_CH); + } cfg1 &= ~ISI_CFG1_FRATE_DIV_MASK; /* Enable linked list */ cfg1 |= isi->pdata.frate | ISI_CFG1_DISCR; - /* Enable codec path and ISI */ - ctrl = ISI_CTRL_CDC | ISI_CTRL_EN; + /* Enable ISI */ + ctrl = ISI_CTRL_EN; + + if (!isi->enable_preview_path) + ctrl |= ISI_CTRL_CDC; + isi_writel(isi, ISI_CTRL, ctrl); isi_writel(isi, ISI_CFG1, cfg1); } @@ -411,7 +483,7 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count) isi_writel(isi, ISI_INTDIS, (u32)~0UL); configure_geometry(isi, icd->user_width, icd->user_height, - icd->current_fmt->code); + icd->current_fmt); spin_lock_irq(&isi->lock); /* Clear any pending interrupt */ @@ -443,15 +515,17 @@ static void stop_streaming(struct vb2_queue *vq) } spin_unlock_irq(&isi->lock); - timeout = jiffies + FRAME_INTERVAL_MILLI_SEC * HZ; - /* Wait until the end of the current frame. */ - while ((isi_readl(isi, ISI_STATUS) & ISI_CTRL_CDC) && - time_before(jiffies, timeout)) - msleep(1); + if (!isi->enable_preview_path) { + timeout = jiffies + FRAME_INTERVAL_MILLI_SEC * HZ; + /* Wait until the end of the current frame. */ + while ((isi_readl(isi, ISI_STATUS) & ISI_CTRL_CDC) && + time_before(jiffies, timeout)) + msleep(1); - if (time_after(jiffies, timeout)) - dev_err(icd->parent, - "Timeout waiting for finishing codec request\n"); + if (time_after(jiffies, timeout)) + dev_err(icd->parent, + "Timeout waiting for finishing codec request\n"); + } /* Disable interrupts */ isi_writel(isi, ISI_INTDIS, @@ -617,6 +691,14 @@ static const struct soc_mbus_pixelfmt isi_camera_formats[] = { .order = SOC_MBUS_ORDER_LE, .layout = SOC_MBUS_LAYOUT_PACKED, }, + { + .fourcc = V4L2_PIX_FMT_RGB565, + .name = "RGB565", + .bits_per_sample = 8, + .packing = SOC_MBUS_PACKING_2X8_PADHI, + .order = SOC_MBUS_ORDER_LE, + .layout = SOC_MBUS_LAYOUT_PACKED, + }, }; /* This will be corrected as we get more formats */ @@ -673,7 +755,7 @@ static int isi_camera_get_formats(struct soc_camera_device *icd, struct soc_camera_format_xlate *xlate) { struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - int formats = 0, ret; + int formats = 0, ret, i, n; /* sensor format */ struct v4l2_subdev_mbus_code_enum code = { .which = V4L2_SUBDEV_FORMAT_ACTIVE, @@ -707,13 +789,13 @@ static int isi_camera_get_formats(struct soc_camera_device *icd, case MEDIA_BUS_FMT_VYUY8_2X8: case MEDIA_BUS_FMT_YUYV8_2X8: case MEDIA_BUS_FMT_YVYU8_2X8: - formats++; - if (xlate) { - xlate->host_fmt = &isi_camera_formats[0]; + n = ARRAY_SIZE(isi_camera_formats); + formats += n; + for (i = 0; xlate && i < n; i++, xlate++) { + xlate->host_fmt = &isi_camera_formats[i]; xlate->code = code.code; - xlate++; dev_dbg(icd->parent, "Providing format %s using code %d\n", - isi_camera_formats[0].name, code.code); + xlate->host_fmt->name, xlate->code); } break; default: diff --git a/drivers/media/platform/soc_camera/atmel-isi.h b/drivers/media/platform/soc_camera/atmel-isi.h index 5acc771d2..0acb32a2b 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.h +++ b/drivers/media/platform/soc_camera/atmel-isi.h @@ -79,6 +79,16 @@ #define ISI_CFG2_IM_VSIZE_MASK (0x7FF << ISI_CFG2_IM_VSIZE_OFFSET) #define ISI_CFG2_IM_HSIZE_MASK (0x7FF << ISI_CFG2_IM_HSIZE_OFFSET) +/* Bitfields in PSIZE */ +#define ISI_PSIZE_PREV_VSIZE_OFFSET 0 +#define ISI_PSIZE_PREV_HSIZE_OFFSET 16 +#define ISI_PSIZE_PREV_VSIZE_MASK (0x3FF << ISI_PSIZE_PREV_VSIZE_OFFSET) +#define ISI_PSIZE_PREV_HSIZE_MASK (0x3FF << ISI_PSIZE_PREV_HSIZE_OFFSET) + +/* Bitfields in PDECF */ +#define ISI_PDECF_DEC_FACTOR_MASK (0xFF << 0) +#define ISI_PDECF_NO_SAMPLING (16) + /* Bitfields in CTRL */ /* Also using in SR(ISI_V2) */ #define ISI_CTRL_EN (1 << 0) diff --git a/drivers/media/platform/soc_camera/mx2_camera.c b/drivers/media/platform/soc_camera/mx2_camera.c index 1f28d21a3..48dd5b785 100644 --- a/drivers/media/platform/soc_camera/mx2_camera.c +++ b/drivers/media/platform/soc_camera/mx2_camera.c @@ -35,11 +35,11 @@ #include <media/videobuf2-v4l2.h> #include <media/videobuf2-dma-contig.h> #include <media/soc_camera.h> -#include <media/soc_mediabus.h> +#include <media/drv-intf/soc_mediabus.h> #include <linux/videodev2.h> -#include <linux/platform_data/camera-mx2.h> +#include <linux/platform_data/media/camera-mx2.h> #include <asm/dma.h> @@ -469,21 +469,15 @@ static void mx2_camera_clock_stop(struct soc_camera_host *ici) * Videobuf operations */ static int mx2_videobuf_setup(struct vb2_queue *vq, - const void *parg, unsigned int *count, unsigned int *num_planes, unsigned int sizes[], void *alloc_ctxs[]) { - const struct v4l2_format *fmt = parg; struct soc_camera_device *icd = soc_camera_from_vb2q(vq); struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct mx2_camera_dev *pcdev = ici->priv; dev_dbg(icd->parent, "count=%d, size=%d\n", *count, sizes[0]); - /* TODO: support for VIDIOC_CREATE_BUFS not ready */ - if (fmt != NULL) - return -ENOTTY; - alloc_ctxs[0] = pcdev->alloc_ctx; sizes[0] = icd->sizeimage; @@ -1351,7 +1345,7 @@ static void mx27_camera_frame_done_emma(struct mx2_camera_dev *pcdev, vb2_get_plane_payload(vb, 0)); list_del_init(&buf->internal.queue); - v4l2_get_timestamp(&vbuf->timestamp); + vb->timestamp = ktime_get_ns(); vbuf->sequence = pcdev->frame_count; if (err) vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); diff --git a/drivers/media/platform/soc_camera/mx3_camera.c b/drivers/media/platform/soc_camera/mx3_camera.c index 49c3a257a..169ed1150 100644 --- a/drivers/media/platform/soc_camera/mx3_camera.c +++ b/drivers/media/platform/soc_camera/mx3_camera.c @@ -23,9 +23,9 @@ #include <media/v4l2-dev.h> #include <media/videobuf2-dma-contig.h> #include <media/soc_camera.h> -#include <media/soc_mediabus.h> +#include <media/drv-intf/soc_mediabus.h> -#include <linux/platform_data/camera-mx3.h> +#include <linux/platform_data/media/camera-mx3.h> #include <linux/platform_data/dma-imx.h> #define MX3_CAM_DRV_NAME "mx3-camera" @@ -155,7 +155,7 @@ static void mx3_cam_dma_done(void *arg) struct mx3_camera_buffer *buf = to_mx3_vb(vb); list_del_init(&buf->queue); - v4l2_get_timestamp(&vb->timestamp); + vb->vb2_buf.timestamp = ktime_get_ns(); vb->field = mx3_cam->field; vb->sequence = mx3_cam->sequence++; vb2_buffer_done(&vb->vb2_buf, VB2_BUF_STATE_DONE); @@ -185,11 +185,9 @@ static void mx3_cam_dma_done(void *arg) * Calculate the __buffer__ (not data) size and number of buffers. */ static int mx3_videobuf_setup(struct vb2_queue *vq, - const void *parg, unsigned int *count, unsigned int *num_planes, unsigned int sizes[], void *alloc_ctxs[]) { - const struct v4l2_format *fmt = parg; struct soc_camera_device *icd = soc_camera_from_vb2q(vq); struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct mx3_camera_dev *mx3_cam = ici->priv; @@ -197,33 +195,6 @@ static int mx3_videobuf_setup(struct vb2_queue *vq, if (!mx3_cam->idmac_channel[0]) return -EINVAL; - if (fmt) { - const struct soc_camera_format_xlate *xlate = soc_camera_xlate_by_fourcc(icd, - fmt->fmt.pix.pixelformat); - unsigned int bytes_per_line; - int ret; - - if (!xlate) - return -EINVAL; - - ret = soc_mbus_bytes_per_line(fmt->fmt.pix.width, - xlate->host_fmt); - if (ret < 0) - return ret; - - bytes_per_line = max_t(u32, fmt->fmt.pix.bytesperline, ret); - - ret = soc_mbus_image_size(xlate->host_fmt, bytes_per_line, - fmt->fmt.pix.height); - if (ret < 0) - return ret; - - sizes[0] = max_t(u32, fmt->fmt.pix.sizeimage, ret); - } else { - /* Called from VIDIOC_REQBUFS or in compatibility mode */ - sizes[0] = icd->sizeimage; - } - alloc_ctxs[0] = mx3_cam->alloc_ctx; if (!vq->num_buffers) @@ -232,9 +203,14 @@ static int mx3_videobuf_setup(struct vb2_queue *vq, if (!*count) *count = 2; + /* Called from VIDIOC_REQBUFS or in compatibility mode */ + if (!*num_planes) + sizes[0] = icd->sizeimage; + else if (sizes[0] < icd->sizeimage) + return -EINVAL; + /* If *num_planes != 0, we have already verified *count. */ - if (!*num_planes && - sizes[0] * *count + mx3_cam->buf_total > MAX_VIDEO_MEM * 1024 * 1024) + if (sizes[0] * *count + mx3_cam->buf_total > MAX_VIDEO_MEM * 1024 * 1024) *count = (MAX_VIDEO_MEM * 1024 * 1024 - mx3_cam->buf_total) / sizes[0]; diff --git a/drivers/media/platform/soc_camera/omap1_camera.c b/drivers/media/platform/soc_camera/omap1_camera.c index ba8dcd11a..bd721e354 100644 --- a/drivers/media/platform/soc_camera/omap1_camera.c +++ b/drivers/media/platform/soc_camera/omap1_camera.c @@ -28,9 +28,9 @@ #include <linux/platform_device.h> #include <linux/slab.h> -#include <media/omap1_camera.h> +#include <linux/platform_data/media/omap1_camera.h> #include <media/soc_camera.h> -#include <media/soc_mediabus.h> +#include <media/drv-intf/soc_mediabus.h> #include <media/videobuf-dma-contig.h> #include <media/videobuf-dma-sg.h> diff --git a/drivers/media/platform/soc_camera/pxa_camera.c b/drivers/media/platform/soc_camera/pxa_camera.c index fcb942de0..415f3bda6 100644 --- a/drivers/media/platform/soc_camera/pxa_camera.c +++ b/drivers/media/platform/soc_camera/pxa_camera.c @@ -33,13 +33,13 @@ #include <media/v4l2-dev.h> #include <media/videobuf-dma-sg.h> #include <media/soc_camera.h> -#include <media/soc_mediabus.h> +#include <media/drv-intf/soc_mediabus.h> #include <media/v4l2-of.h> #include <linux/videodev2.h> #include <mach/dma.h> -#include <linux/platform_data/camera-pxa.h> +#include <linux/platform_data/media/camera-pxa.h> #define PXA_CAM_VERSION "0.0.6" #define PXA_CAM_DRV_NAME "pxa27x-camera" diff --git a/drivers/media/platform/soc_camera/rcar_vin.c b/drivers/media/platform/soc_camera/rcar_vin.c index efe57b23f..b7fd695b9 100644 --- a/drivers/media/platform/soc_camera/rcar_vin.c +++ b/drivers/media/platform/soc_camera/rcar_vin.c @@ -21,14 +21,13 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/of_device.h> -#include <linux/platform_data/camera-rcar.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/slab.h> #include <linux/videodev2.h> #include <media/soc_camera.h> -#include <media/soc_mediabus.h> +#include <media/drv-intf/soc_mediabus.h> #include <media/v4l2-common.h> #include <media/v4l2-dev.h> #include <media/v4l2-device.h> @@ -138,6 +137,11 @@ #define TIMEOUT_MS 100 +#define RCAR_VIN_HSYNC_ACTIVE_LOW (1 << 0) +#define RCAR_VIN_VSYNC_ACTIVE_LOW (1 << 1) +#define RCAR_VIN_BT601 (1 << 2) +#define RCAR_VIN_BT656 (1 << 3) + enum chip_id { RCAR_GEN2, RCAR_H1, @@ -527,46 +531,14 @@ struct rcar_vin_cam { * required */ static int rcar_vin_videobuf_setup(struct vb2_queue *vq, - const void *parg, unsigned int *count, unsigned int *num_planes, unsigned int sizes[], void *alloc_ctxs[]) { - const struct v4l2_format *fmt = parg; struct soc_camera_device *icd = soc_camera_from_vb2q(vq); struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct rcar_vin_priv *priv = ici->priv; - if (fmt) { - const struct soc_camera_format_xlate *xlate; - unsigned int bytes_per_line; - int ret; - - if (fmt->fmt.pix.sizeimage < icd->sizeimage) - return -EINVAL; - - xlate = soc_camera_xlate_by_fourcc(icd, - fmt->fmt.pix.pixelformat); - if (!xlate) - return -EINVAL; - ret = soc_mbus_bytes_per_line(fmt->fmt.pix.width, - xlate->host_fmt); - if (ret < 0) - return ret; - - bytes_per_line = max_t(u32, fmt->fmt.pix.bytesperline, ret); - - ret = soc_mbus_image_size(xlate->host_fmt, bytes_per_line, - fmt->fmt.pix.height); - if (ret < 0) - return ret; - - sizes[0] = max_t(u32, fmt->fmt.pix.sizeimage, ret); - } else { - /* Called from VIDIOC_REQBUFS or in compatibility mode */ - sizes[0] = icd->sizeimage; - } - alloc_ctxs[0] = priv->alloc_ctx; if (!vq->num_buffers) @@ -576,14 +548,18 @@ static int rcar_vin_videobuf_setup(struct vb2_queue *vq, *count = 2; priv->vb_count = *count; - *num_planes = 1; - /* Number of hardware slots */ if (is_continuous_transfer(priv)) priv->nr_hw_slots = MAX_BUFFER_NUM; else priv->nr_hw_slots = 1; + if (*num_planes) + return sizes[0] < icd->sizeimage ? -EINVAL : 0; + + sizes[0] = icd->sizeimage; + *num_planes = 1; + dev_dbg(icd->parent, "count=%d, size=%u\n", *count, sizes[0]); return 0; @@ -912,7 +888,7 @@ static irqreturn_t rcar_vin_irq(int irq, void *data) priv->queue_buf[slot]->field = priv->field; priv->queue_buf[slot]->sequence = priv->sequence++; - v4l2_get_timestamp(&priv->queue_buf[slot]->timestamp); + priv->queue_buf[slot]->vb2_buf.timestamp = ktime_get_ns(); vb2_buffer_done(&priv->queue_buf[slot]->vb2_buf, VB2_BUF_STATE_DONE); priv->queue_buf[slot] = NULL; @@ -1853,63 +1829,43 @@ static const struct of_device_id rcar_vin_of_table[] = { MODULE_DEVICE_TABLE(of, rcar_vin_of_table); #endif -static struct platform_device_id rcar_vin_id_table[] = { - { "r8a7779-vin", RCAR_H1 }, - { "r8a7778-vin", RCAR_M1 }, - { "uPD35004-vin", RCAR_E1 }, - {}, -}; -MODULE_DEVICE_TABLE(platform, rcar_vin_id_table); - static int rcar_vin_probe(struct platform_device *pdev) { const struct of_device_id *match = NULL; struct rcar_vin_priv *priv; + struct v4l2_of_endpoint ep; + struct device_node *np; struct resource *mem; - struct rcar_vin_platform_data *pdata; unsigned int pdata_flags; int irq, ret; - if (pdev->dev.of_node) { - struct v4l2_of_endpoint ep; - struct device_node *np; + match = of_match_device(of_match_ptr(rcar_vin_of_table), &pdev->dev); - match = of_match_device(of_match_ptr(rcar_vin_of_table), - &pdev->dev); - - np = of_graph_get_next_endpoint(pdev->dev.of_node, NULL); - if (!np) { - dev_err(&pdev->dev, "could not find endpoint\n"); - return -EINVAL; - } + np = of_graph_get_next_endpoint(pdev->dev.of_node, NULL); + if (!np) { + dev_err(&pdev->dev, "could not find endpoint\n"); + return -EINVAL; + } - ret = v4l2_of_parse_endpoint(np, &ep); - if (ret) { - dev_err(&pdev->dev, "could not parse endpoint\n"); - return ret; - } + ret = v4l2_of_parse_endpoint(np, &ep); + if (ret) { + dev_err(&pdev->dev, "could not parse endpoint\n"); + return ret; + } - if (ep.bus_type == V4L2_MBUS_BT656) - pdata_flags = RCAR_VIN_BT656; - else { - pdata_flags = 0; - if (ep.bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) - pdata_flags |= RCAR_VIN_HSYNC_ACTIVE_LOW; - if (ep.bus.parallel.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) - pdata_flags |= RCAR_VIN_VSYNC_ACTIVE_LOW; - } + if (ep.bus_type == V4L2_MBUS_BT656) + pdata_flags = RCAR_VIN_BT656; + else { + pdata_flags = 0; + if (ep.bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) + pdata_flags |= RCAR_VIN_HSYNC_ACTIVE_LOW; + if (ep.bus.parallel.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) + pdata_flags |= RCAR_VIN_VSYNC_ACTIVE_LOW; + } - of_node_put(np); + of_node_put(np); - dev_dbg(&pdev->dev, "pdata_flags = %08x\n", pdata_flags); - } else { - pdata = pdev->dev.platform_data; - if (!pdata || !pdata->flags) { - dev_err(&pdev->dev, "platform data not set\n"); - return -EINVAL; - } - pdata_flags = pdata->flags; - } + dev_dbg(&pdev->dev, "pdata_flags = %08x\n", pdata_flags); mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (mem == NULL) @@ -1992,7 +1948,6 @@ static struct platform_driver rcar_vin_driver = { .name = DRV_NAME, .of_match_table = of_match_ptr(rcar_vin_of_table), }, - .id_table = rcar_vin_id_table, }; module_platform_driver(rcar_vin_driver); diff --git a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c index 67a669d82..90c87f2b4 100644 --- a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c +++ b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c @@ -40,11 +40,11 @@ #include <media/v4l2-common.h> #include <media/v4l2-dev.h> #include <media/soc_camera.h> -#include <media/sh_mobile_ceu.h> -#include <media/sh_mobile_csi2.h> +#include <media/drv-intf/sh_mobile_ceu.h> +#include <media/drv-intf/sh_mobile_csi2.h> #include <media/videobuf2-dma-contig.h> #include <media/v4l2-mediabus.h> -#include <media/soc_mediabus.h> +#include <media/drv-intf/soc_mediabus.h> #include "soc_scale_crop.h" @@ -210,43 +210,14 @@ static int sh_mobile_ceu_soft_reset(struct sh_mobile_ceu_dev *pcdev) * for the current frame format if required */ static int sh_mobile_ceu_videobuf_setup(struct vb2_queue *vq, - const void *parg, unsigned int *count, unsigned int *num_planes, unsigned int sizes[], void *alloc_ctxs[]) { - const struct v4l2_format *fmt = parg; struct soc_camera_device *icd = container_of(vq, struct soc_camera_device, vb2_vidq); struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct sh_mobile_ceu_dev *pcdev = ici->priv; - if (fmt) { - const struct soc_camera_format_xlate *xlate = soc_camera_xlate_by_fourcc(icd, - fmt->fmt.pix.pixelformat); - unsigned int bytes_per_line; - int ret; - - if (!xlate) - return -EINVAL; - - ret = soc_mbus_bytes_per_line(fmt->fmt.pix.width, - xlate->host_fmt); - if (ret < 0) - return ret; - - bytes_per_line = max_t(u32, fmt->fmt.pix.bytesperline, ret); - - ret = soc_mbus_image_size(xlate->host_fmt, bytes_per_line, - fmt->fmt.pix.height); - if (ret < 0) - return ret; - - sizes[0] = max_t(u32, fmt->fmt.pix.sizeimage, ret); - } else { - /* Called from VIDIOC_REQBUFS or in compatibility mode */ - sizes[0] = icd->sizeimage; - } - alloc_ctxs[0] = pcdev->alloc_ctx; if (!vq->num_buffers) @@ -255,8 +226,14 @@ static int sh_mobile_ceu_videobuf_setup(struct vb2_queue *vq, if (!*count) *count = 2; + /* Called from VIDIOC_REQBUFS or in compatibility mode */ + if (!*num_planes) + sizes[0] = icd->sizeimage; + else if (sizes[0] < icd->sizeimage) + return -EINVAL; + /* If *num_planes != 0, we have already verified *count. */ - if (pcdev->video_limit && !*num_planes) { + if (pcdev->video_limit) { size_t size = PAGE_ALIGN(sizes[0]) * *count; if (size + pcdev->buf_total > pcdev->video_limit) @@ -533,7 +510,7 @@ static irqreturn_t sh_mobile_ceu_irq(int irq, void *data) pcdev->active = NULL; ret = sh_mobile_ceu_capture(pcdev); - v4l2_get_timestamp(&vbuf->timestamp); + vbuf->vb2_buf.timestamp = ktime_get_ns(); if (!ret) { vbuf->field = pcdev->field; vbuf->sequence = pcdev->sequence++; diff --git a/drivers/media/platform/soc_camera/sh_mobile_csi2.c b/drivers/media/platform/soc_camera/sh_mobile_csi2.c index 12d3626ec..09b18365a 100644 --- a/drivers/media/platform/soc_camera/sh_mobile_csi2.c +++ b/drivers/media/platform/soc_camera/sh_mobile_csi2.c @@ -18,10 +18,10 @@ #include <linux/videodev2.h> #include <linux/module.h> -#include <media/sh_mobile_ceu.h> -#include <media/sh_mobile_csi2.h> +#include <media/drv-intf/sh_mobile_ceu.h> +#include <media/drv-intf/sh_mobile_csi2.h> #include <media/soc_camera.h> -#include <media/soc_mediabus.h> +#include <media/drv-intf/soc_mediabus.h> #include <media/v4l2-common.h> #include <media/v4l2-dev.h> #include <media/v4l2-device.h> diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index dc98122e7..46c7186f7 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c @@ -30,7 +30,7 @@ #include <linux/vmalloc.h> #include <media/soc_camera.h> -#include <media/soc_mediabus.h> +#include <media/drv-intf/soc_mediabus.h> #include <media/v4l2-async.h> #include <media/v4l2-clk.h> #include <media/v4l2-common.h> @@ -1360,7 +1360,7 @@ static int soc_camera_i2c_init(struct soc_camera_device *icd, struct soc_camera_host_desc *shd = &sdesc->host_desc; struct i2c_adapter *adap; struct v4l2_subdev *subdev; - char clk_name[V4L2_SUBDEV_NAME_SIZE]; + char clk_name[V4L2_CLK_NAME_SIZE]; int ret; /* First find out how we link the main client */ @@ -1391,8 +1391,8 @@ static int soc_camera_i2c_init(struct soc_camera_device *icd, ssdd->sd_pdata.regulators = NULL; shd->board_info->platform_data = ssdd; - snprintf(clk_name, sizeof(clk_name), "%d-%04x", - shd->i2c_adapter_id, shd->board_info->addr); + v4l2_clk_name_i2c(clk_name, sizeof(clk_name), + shd->i2c_adapter_id, shd->board_info->addr); icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, icd); if (IS_ERR(icd->clk)) { @@ -1493,6 +1493,8 @@ static void soc_camera_async_unbind(struct v4l2_async_notifier *notifier, struct soc_camera_async_client, notifier); struct soc_camera_device *icd = platform_get_drvdata(sasc->pdev); + icd->control = NULL; + if (icd->clk) { v4l2_clk_unregister(icd->clk); icd->clk = NULL; @@ -1526,7 +1528,7 @@ static int scan_async_group(struct soc_camera_host *ici, struct soc_camera_async_client *sasc; struct soc_camera_device *icd; struct soc_camera_desc sdesc = {.host_desc.bus_id = ici->nr,}; - char clk_name[V4L2_SUBDEV_NAME_SIZE]; + char clk_name[V4L2_CLK_NAME_SIZE]; unsigned int i; int ret; @@ -1572,8 +1574,9 @@ static int scan_async_group(struct soc_camera_host *ici, icd->sasc = sasc; icd->parent = ici->v4l2_dev.dev; - snprintf(clk_name, sizeof(clk_name), "%d-%04x", - sasd->asd.match.i2c.adapter_id, sasd->asd.match.i2c.address); + v4l2_clk_name_i2c(clk_name, sizeof(clk_name), + sasd->asd.match.i2c.adapter_id, + sasd->asd.match.i2c.address); icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, icd); if (IS_ERR(icd->clk)) { @@ -1631,7 +1634,7 @@ static int soc_of_bind(struct soc_camera_host *ici, struct soc_camera_async_client *sasc; struct soc_of_info *info; struct i2c_client *client; - char clk_name[V4L2_SUBDEV_NAME_SIZE + 32]; + char clk_name[V4L2_CLK_NAME_SIZE]; int ret; /* allocate a new subdev and add match info to it */ @@ -1674,11 +1677,11 @@ static int soc_of_bind(struct soc_camera_host *ici, client = of_find_i2c_device_by_node(remote); if (client) - snprintf(clk_name, sizeof(clk_name), "%d-%04x", - client->adapter->nr, client->addr); + v4l2_clk_name_i2c(clk_name, sizeof(clk_name), + client->adapter->nr, client->addr); else - snprintf(clk_name, sizeof(clk_name), "of-%s", - of_node_full_name(remote)); + v4l2_clk_name_of(clk_name, sizeof(clk_name), + of_node_full_name(remote)); icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, icd); if (IS_ERR(icd->clk)) { diff --git a/drivers/media/platform/soc_camera/soc_camera_platform.c b/drivers/media/platform/soc_camera/soc_camera_platform.c index cc8eb0758..a51d2a429 100644 --- a/drivers/media/platform/soc_camera/soc_camera_platform.c +++ b/drivers/media/platform/soc_camera/soc_camera_platform.c @@ -18,7 +18,7 @@ #include <linux/videodev2.h> #include <media/v4l2-subdev.h> #include <media/soc_camera.h> -#include <media/soc_camera_platform.h> +#include <linux/platform_data/media/soc_camera_platform.h> struct soc_camera_platform_priv { struct v4l2_subdev subdev; diff --git a/drivers/media/platform/soc_camera/soc_mediabus.c b/drivers/media/platform/soc_camera/soc_mediabus.c index 1dbcd4266..e3e665e1c 100644 --- a/drivers/media/platform/soc_camera/soc_mediabus.c +++ b/drivers/media/platform/soc_camera/soc_mediabus.c @@ -13,7 +13,7 @@ #include <media/v4l2-device.h> #include <media/v4l2-mediabus.h> -#include <media/soc_mediabus.h> +#include <media/drv-intf/soc_mediabus.h> static const struct soc_mbus_lookup mbus_fmt[] = { { diff --git a/drivers/media/platform/sti/bdisp/bdisp-v4l2.c b/drivers/media/platform/sti/bdisp/bdisp-v4l2.c index a0d267e01..d12a419c0 100644 --- a/drivers/media/platform/sti/bdisp/bdisp-v4l2.c +++ b/drivers/media/platform/sti/bdisp/bdisp-v4l2.c @@ -191,7 +191,7 @@ static void bdisp_job_finish(struct bdisp_ctx *ctx, int vb_state) dst_vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); if (src_vb && dst_vb) { - dst_vb->timestamp = src_vb->timestamp; + dst_vb->vb2_buf.timestamp = src_vb->vb2_buf.timestamp; dst_vb->timecode = src_vb->timecode; dst_vb->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; dst_vb->flags |= src_vb->flags & @@ -297,7 +297,7 @@ static int bdisp_get_bufs(struct bdisp_ctx *ctx) if (ret) return ret; - dst_vb->timestamp = src_vb->timestamp; + dst_vb->vb2_buf.timestamp = src_vb->vb2_buf.timestamp; return 0; } @@ -438,11 +438,9 @@ static void bdisp_ctrls_delete(struct bdisp_ctx *ctx) } static int bdisp_queue_setup(struct vb2_queue *vq, - const void *parg, unsigned int *nb_buf, unsigned int *nb_planes, unsigned int sizes[], void *allocators[]) { - const struct v4l2_format *fmt = parg; struct bdisp_ctx *ctx = vb2_get_drv_priv(vq); struct bdisp_frame *frame = ctx_get_frame(ctx, vq->type); @@ -455,13 +453,13 @@ static int bdisp_queue_setup(struct vb2_queue *vq, dev_err(ctx->bdisp_dev->dev, "Invalid format\n"); return -EINVAL; } + allocators[0] = ctx->bdisp_dev->alloc_ctx; - if (fmt && fmt->fmt.pix.sizeimage < frame->sizeimage) - return -EINVAL; + if (*nb_planes) + return sizes[0] < frame->sizeimage ? -EINVAL : 0; *nb_planes = 1; - sizes[0] = fmt ? fmt->fmt.pix.sizeimage : frame->sizeimage; - allocators[0] = ctx->bdisp_dev->alloc_ctx; + sizes[0] = frame->sizeimage; return 0; } diff --git a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-common.c b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-common.c index 95223ab71..2dfbe8ab5 100644 --- a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-common.c +++ b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-common.c @@ -209,18 +209,18 @@ void c8sectpfe_tuner_unregister_frontend(struct c8sectpfe *c8sectpfe, tsin = fei->channel_data[n]; - if (tsin && tsin->frontend) { - dvb_unregister_frontend(tsin->frontend); - dvb_frontend_detach(tsin->frontend); - } + if (tsin) { + if (tsin->frontend) { + dvb_unregister_frontend(tsin->frontend); + dvb_frontend_detach(tsin->frontend); + } - if (tsin && tsin->i2c_adapter) i2c_put_adapter(tsin->i2c_adapter); - if (tsin && tsin->i2c_client) { - if (tsin->i2c_client->dev.driver->owner) + if (tsin->i2c_client) { module_put(tsin->i2c_client->dev.driver->owner); - i2c_unregister_device(tsin->i2c_client); + i2c_unregister_device(tsin->i2c_client); + } } } diff --git a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c index 2c6499d06..d9d57645e 100644 --- a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c +++ b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c @@ -823,7 +823,7 @@ static int c8sectpfe_probe(struct platform_device *pdev) } of_node_put(i2c_bus); - tsin->rst_gpio = of_get_named_gpio(child, "rst-gpio", 0); + tsin->rst_gpio = of_get_named_gpio(child, "reset-gpios", 0); ret = gpio_is_valid(tsin->rst_gpio); if (!ret) { diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index de24effd9..1fa00c2cf 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c @@ -1288,7 +1288,7 @@ static irqreturn_t vpe_irq(int irq_vpe, void *data) d_vb = ctx->dst_vb; d_vb->flags = s_vb->flags; - d_vb->timestamp = s_vb->timestamp; + d_vb->vb2_buf.timestamp = s_vb->vb2_buf.timestamp; if (s_vb->flags & V4L2_BUF_FLAG_TIMECODE) d_vb->timecode = s_vb->timecode; @@ -1796,7 +1796,6 @@ static const struct v4l2_ioctl_ops vpe_ioctl_ops = { * Queue operations */ static int vpe_queue_setup(struct vb2_queue *vq, - const void *parg, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) { diff --git a/drivers/media/platform/timblogiw.c b/drivers/media/platform/timblogiw.c index 5820e45b3..113c9f3c0 100644 --- a/drivers/media/platform/timblogiw.c +++ b/drivers/media/platform/timblogiw.c @@ -31,7 +31,7 @@ #include <media/v4l2-ioctl.h> #include <media/v4l2-device.h> #include <media/videobuf-dma-contig.h> -#include <media/timb_video.h> +#include <linux/platform_data/media/timb_video.h> #define DRIVER_NAME "timb-video" diff --git a/drivers/media/platform/via-camera.c b/drivers/media/platform/via-camera.c index 32e4ff46d..1254f7e4d 100644 --- a/drivers/media/platform/via-camera.c +++ b/drivers/media/platform/via-camera.c @@ -19,7 +19,7 @@ #include <media/v4l2-ioctl.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-image-sizes.h> -#include <media/ov7670.h> +#include <media/i2c/ov7670.h> #include <media/videobuf-dma-sg.h> #include <linux/delay.h> #include <linux/dma-mapping.h> diff --git a/drivers/media/platform/vim2m.c b/drivers/media/platform/vim2m.c index e18fb9f9e..418113c99 100644 --- a/drivers/media/platform/vim2m.c +++ b/drivers/media/platform/vim2m.c @@ -235,7 +235,7 @@ static int device_process(struct vim2m_ctx *ctx, out_vb->sequence = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE)->sequence++; in_vb->sequence = q_data->sequence++; - out_vb->timestamp = in_vb->timestamp; + out_vb->vb2_buf.timestamp = in_vb->vb2_buf.timestamp; if (in_vb->flags & V4L2_BUF_FLAG_TIMECODE) out_vb->timecode = in_vb->timecode; @@ -710,11 +710,9 @@ static const struct v4l2_ioctl_ops vim2m_ioctl_ops = { */ static int vim2m_queue_setup(struct vb2_queue *vq, - const void *parg, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) { - const struct v4l2_format *fmt = parg; struct vim2m_ctx *ctx = vb2_get_drv_priv(vq); struct vim2m_q_data *q_data; unsigned int size, count = *nbuffers; @@ -723,17 +721,14 @@ static int vim2m_queue_setup(struct vb2_queue *vq, size = q_data->width * q_data->height * q_data->fmt->depth >> 3; - if (fmt) { - if (fmt->fmt.pix.sizeimage < size) - return -EINVAL; - size = fmt->fmt.pix.sizeimage; - } - while (size * count > MEM2MEM_VID_MEM_LIMIT) (count)--; + *nbuffers = count; + + if (*nplanes) + return sizes[0] < size ? -EINVAL : 0; *nplanes = 1; - *nbuffers = count; sizes[0] = size; /* diff --git a/drivers/media/platform/vivid/vivid-core.h b/drivers/media/platform/vivid/vivid-core.h index 55b304a70..751c1ba39 100644 --- a/drivers/media/platform/vivid/vivid-core.h +++ b/drivers/media/platform/vivid/vivid-core.h @@ -264,6 +264,7 @@ struct vivid_dev { bool vflip; bool vbi_cap_interlaced; bool loop_video; + bool reduced_fps; /* Framebuffer */ unsigned long video_pbase; @@ -285,7 +286,7 @@ struct vivid_dev { bool dqbuf_error; bool seq_wrap; bool time_wrap; - __kernel_time_t time_wrap_offset; + u64 time_wrap_offset; unsigned perc_dropped_buffers; enum vivid_signal_mode std_signal_mode; unsigned query_std_last; diff --git a/drivers/media/platform/vivid/vivid-ctrls.c b/drivers/media/platform/vivid/vivid-ctrls.c index f41ac0b01..b98089c95 100644 --- a/drivers/media/platform/vivid/vivid-ctrls.c +++ b/drivers/media/platform/vivid/vivid-ctrls.c @@ -78,6 +78,7 @@ #define VIVID_CID_TIME_WRAP (VIVID_CID_VIVID_BASE + 39) #define VIVID_CID_MAX_EDID_BLOCKS (VIVID_CID_VIVID_BASE + 40) #define VIVID_CID_PERCENTAGE_FILL (VIVID_CID_VIVID_BASE + 41) +#define VIVID_CID_REDUCED_FPS (VIVID_CID_VIVID_BASE + 42) #define VIVID_CID_STD_SIGNAL_MODE (VIVID_CID_VIVID_BASE + 60) #define VIVID_CID_STANDARD (VIVID_CID_VIVID_BASE + 61) @@ -424,6 +425,10 @@ static int vivid_vid_cap_s_ctrl(struct v4l2_ctrl *ctrl) dev->sensor_vflip = ctrl->val; tpg_s_vflip(&dev->tpg, dev->sensor_vflip ^ dev->vflip); break; + case VIVID_CID_REDUCED_FPS: + dev->reduced_fps = ctrl->val; + vivid_update_format_cap(dev, true); + break; case VIVID_CID_HAS_CROP_CAP: dev->has_crop_cap = ctrl->val; vivid_update_format_cap(dev, true); @@ -601,6 +606,15 @@ static const struct v4l2_ctrl_config vivid_ctrl_vflip = { .step = 1, }; +static const struct v4l2_ctrl_config vivid_ctrl_reduced_fps = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_REDUCED_FPS, + .name = "Reduced Framerate", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .step = 1, +}; + static const struct v4l2_ctrl_config vivid_ctrl_has_crop_cap = { .ops = &vivid_vid_cap_ctrl_ops, .id = VIVID_CID_HAS_CROP_CAP, @@ -940,7 +954,7 @@ static const struct v4l2_ctrl_config vivid_ctrl_has_scaler_out = { static int vivid_streaming_s_ctrl(struct v4l2_ctrl *ctrl) { struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_streaming); - struct timeval tv; + u64 rem; switch (ctrl->id) { case VIVID_CID_DQBUF_ERROR: @@ -979,8 +993,16 @@ static int vivid_streaming_s_ctrl(struct v4l2_ctrl *ctrl) dev->time_wrap_offset = 0; break; } - v4l2_get_timestamp(&tv); - dev->time_wrap_offset = -tv.tv_sec - 16; + /* + * We want to set the time 16 seconds before the 32 bit tv_sec + * value of struct timeval would wrap around. So first we + * calculate ktime_get_ns() % ((1 << 32) * NSEC_PER_SEC), and + * then we set the offset to ((1 << 32) - 16) * NSEC_PER_SEC). + */ + div64_u64_rem(ktime_get_ns(), + 0x100000000ULL * NSEC_PER_SEC, &rem); + dev->time_wrap_offset = + (0x100000000ULL - 16) * NSEC_PER_SEC - rem; break; } return 0; @@ -1340,11 +1362,13 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap, v4l2_ctrl_handler_init(hdl_vid_cap, 55); v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_class, NULL); v4l2_ctrl_handler_init(hdl_vid_out, 26); - v4l2_ctrl_new_custom(hdl_vid_out, &vivid_ctrl_class, NULL); + if (!no_error_inj) + v4l2_ctrl_new_custom(hdl_vid_out, &vivid_ctrl_class, NULL); v4l2_ctrl_handler_init(hdl_vbi_cap, 21); v4l2_ctrl_new_custom(hdl_vbi_cap, &vivid_ctrl_class, NULL); v4l2_ctrl_handler_init(hdl_vbi_out, 19); - v4l2_ctrl_new_custom(hdl_vbi_out, &vivid_ctrl_class, NULL); + if (!no_error_inj) + v4l2_ctrl_new_custom(hdl_vbi_out, &vivid_ctrl_class, NULL); v4l2_ctrl_handler_init(hdl_radio_rx, 17); v4l2_ctrl_new_custom(hdl_radio_rx, &vivid_ctrl_class, NULL); v4l2_ctrl_handler_init(hdl_radio_tx, 17); @@ -1414,6 +1438,7 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap, v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_vflip, NULL); v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_insert_sav, NULL); v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_insert_eav, NULL); + v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_reduced_fps, NULL); if (show_ccs_cap) { dev->ctrl_has_crop_cap = v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_has_crop_cap, NULL); diff --git a/drivers/media/platform/vivid/vivid-kthread-cap.c b/drivers/media/platform/vivid/vivid-kthread-cap.c index 83cc6d3b4..903428194 100644 --- a/drivers/media/platform/vivid/vivid-kthread-cap.c +++ b/drivers/media/platform/vivid/vivid-kthread-cap.c @@ -441,7 +441,7 @@ static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf) * "Start of Exposure". */ if (dev->tstamp_src_is_soe) - v4l2_get_timestamp(&buf->vb.timestamp); + buf->vb.vb2_buf.timestamp = ktime_get_ns(); if (dev->field_cap == V4L2_FIELD_ALTERNATE) { /* * 60 Hz standards start with the bottom field, 50 Hz standards @@ -558,8 +558,8 @@ static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf) * the timestamp now. */ if (!dev->tstamp_src_is_soe) - v4l2_get_timestamp(&buf->vb.timestamp); - buf->vb.timestamp.tv_sec += dev->time_wrap_offset; + buf->vb.vb2_buf.timestamp = ktime_get_ns(); + buf->vb.vb2_buf.timestamp += dev->time_wrap_offset; } /* diff --git a/drivers/media/platform/vivid/vivid-kthread-out.c b/drivers/media/platform/vivid/vivid-kthread-out.c index c2c46dcdb..98eed5889 100644 --- a/drivers/media/platform/vivid/vivid-kthread-out.c +++ b/drivers/media/platform/vivid/vivid-kthread-out.c @@ -95,8 +95,8 @@ static void vivid_thread_vid_out_tick(struct vivid_dev *dev) */ vid_out_buf->vb.sequence /= 2; } - v4l2_get_timestamp(&vid_out_buf->vb.timestamp); - vid_out_buf->vb.timestamp.tv_sec += dev->time_wrap_offset; + vid_out_buf->vb.vb2_buf.timestamp = + ktime_get_ns() + dev->time_wrap_offset; vb2_buffer_done(&vid_out_buf->vb.vb2_buf, dev->dqbuf_error ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); dprintk(dev, 2, "vid_out buffer %d done\n", @@ -108,8 +108,8 @@ static void vivid_thread_vid_out_tick(struct vivid_dev *dev) vivid_sliced_vbi_out_process(dev, vbi_out_buf); vbi_out_buf->vb.sequence = dev->vbi_out_seq_count; - v4l2_get_timestamp(&vbi_out_buf->vb.timestamp); - vbi_out_buf->vb.timestamp.tv_sec += dev->time_wrap_offset; + vbi_out_buf->vb.vb2_buf.timestamp = + ktime_get_ns() + dev->time_wrap_offset; vb2_buffer_done(&vbi_out_buf->vb.vb2_buf, dev->dqbuf_error ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); dprintk(dev, 2, "vbi_out buffer %d done\n", diff --git a/drivers/media/platform/vivid/vivid-sdr-cap.c b/drivers/media/platform/vivid/vivid-sdr-cap.c index 082c40176..3d1604cb9 100644 --- a/drivers/media/platform/vivid/vivid-sdr-cap.c +++ b/drivers/media/platform/vivid/vivid-sdr-cap.c @@ -117,8 +117,8 @@ static void vivid_thread_sdr_cap_tick(struct vivid_dev *dev) if (sdr_cap_buf) { sdr_cap_buf->vb.sequence = dev->sdr_cap_seq_count; vivid_sdr_cap_process(dev, sdr_cap_buf); - v4l2_get_timestamp(&sdr_cap_buf->vb.timestamp); - sdr_cap_buf->vb.timestamp.tv_sec += dev->time_wrap_offset; + sdr_cap_buf->vb.vb2_buf.timestamp = + ktime_get_ns() + dev->time_wrap_offset; vb2_buffer_done(&sdr_cap_buf->vb.vb2_buf, dev->dqbuf_error ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); dev->dqbuf_error = false; @@ -213,7 +213,7 @@ static int vivid_thread_sdr_cap(void *data) return 0; } -static int sdr_cap_queue_setup(struct vb2_queue *vq, const void *parg, +static int sdr_cap_queue_setup(struct vb2_queue *vq, unsigned *nbuffers, unsigned *nplanes, unsigned sizes[], void *alloc_ctxs[]) { diff --git a/drivers/media/platform/vivid/vivid-vbi-cap.c b/drivers/media/platform/vivid/vivid-vbi-cap.c index e903d023e..cda45a582 100644 --- a/drivers/media/platform/vivid/vivid-vbi-cap.c +++ b/drivers/media/platform/vivid/vivid-vbi-cap.c @@ -108,8 +108,7 @@ void vivid_raw_vbi_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf) if (!VIVID_INVALID_SIGNAL(dev->std_signal_mode)) vivid_vbi_gen_raw(&dev->vbi_gen, &vbi, vbuf); - v4l2_get_timestamp(&buf->vb.timestamp); - buf->vb.timestamp.tv_sec += dev->time_wrap_offset; + buf->vb.vb2_buf.timestamp = ktime_get_ns() + dev->time_wrap_offset; } @@ -133,11 +132,10 @@ void vivid_sliced_vbi_cap_process(struct vivid_dev *dev, vbuf[i] = dev->vbi_gen.data[i]; } - v4l2_get_timestamp(&buf->vb.timestamp); - buf->vb.timestamp.tv_sec += dev->time_wrap_offset; + buf->vb.vb2_buf.timestamp = ktime_get_ns() + dev->time_wrap_offset; } -static int vbi_cap_queue_setup(struct vb2_queue *vq, const void *parg, +static int vbi_cap_queue_setup(struct vb2_queue *vq, unsigned *nbuffers, unsigned *nplanes, unsigned sizes[], void *alloc_ctxs[]) { diff --git a/drivers/media/platform/vivid/vivid-vbi-out.c b/drivers/media/platform/vivid/vivid-vbi-out.c index 75c5709f9..3c5a469e6 100644 --- a/drivers/media/platform/vivid/vivid-vbi-out.c +++ b/drivers/media/platform/vivid/vivid-vbi-out.c @@ -27,7 +27,7 @@ #include "vivid-vbi-out.h" #include "vivid-vbi-cap.h" -static int vbi_out_queue_setup(struct vb2_queue *vq, const void *parg, +static int vbi_out_queue_setup(struct vb2_queue *vq, unsigned *nbuffers, unsigned *nplanes, unsigned sizes[], void *alloc_ctxs[]) { diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c index ef5412311..b84f081c1 100644 --- a/drivers/media/platform/vivid/vivid-vid-cap.c +++ b/drivers/media/platform/vivid/vivid-vid-cap.c @@ -95,11 +95,10 @@ static const struct v4l2_discrete_probe webcam_probe = { VIVID_WEBCAM_SIZES }; -static int vid_cap_queue_setup(struct vb2_queue *vq, const void *parg, +static int vid_cap_queue_setup(struct vb2_queue *vq, unsigned *nbuffers, unsigned *nplanes, unsigned sizes[], void *alloc_ctxs[]) { - const struct v4l2_format *fmt = parg; struct vivid_dev *dev = vb2_get_drv_priv(vq); unsigned buffers = tpg_g_buffers(&dev->tpg); unsigned h = dev->fmt_cap_rect.height; @@ -122,27 +121,16 @@ static int vid_cap_queue_setup(struct vb2_queue *vq, const void *parg, dev->queue_setup_error = false; return -EINVAL; } - if (fmt) { - const struct v4l2_pix_format_mplane *mp; - struct v4l2_format mp_fmt; - const struct vivid_fmt *vfmt; - - if (!V4L2_TYPE_IS_MULTIPLANAR(fmt->type)) { - fmt_sp2mp(fmt, &mp_fmt); - fmt = &mp_fmt; - } - mp = &fmt->fmt.pix_mp; + if (*nplanes) { /* - * Check if the number of planes in the specified format match + * Check if the number of requested planes match * the number of buffers in the current format. You can't mix that. */ - if (mp->num_planes != buffers) + if (*nplanes != buffers) return -EINVAL; - vfmt = vivid_get_format(dev, mp->pixelformat); for (p = 0; p < buffers; p++) { - sizes[p] = mp->plane_fmt[p].sizeimage; if (sizes[p] < tpg_g_line_width(&dev->tpg, p) * h + - vfmt->data_offset[p]) + dev->fmt_cap->data_offset[p]) return -EINVAL; } } else { @@ -405,6 +393,7 @@ void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls) { struct v4l2_bt_timings *bt = &dev->dv_timings_cap.bt; unsigned size; + u64 pixelclock; switch (dev->input_type[dev->input]) { case WEBCAM: @@ -434,8 +423,15 @@ void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls) dev->src_rect.width = bt->width; dev->src_rect.height = bt->height; size = V4L2_DV_BT_FRAME_WIDTH(bt) * V4L2_DV_BT_FRAME_HEIGHT(bt); + if (dev->reduced_fps && can_reduce_fps(bt)) { + pixelclock = div_u64(bt->pixelclock * 1000, 1001); + bt->flags |= V4L2_DV_FL_REDUCED_FPS; + } else { + pixelclock = bt->pixelclock; + bt->flags &= ~V4L2_DV_FL_REDUCED_FPS; + } dev->timeperframe_vid_cap = (struct v4l2_fract) { - size / 100, (u32)bt->pixelclock / 100 + size / 100, (u32)pixelclock / 100 }; if (bt->interlaced) dev->field_cap = V4L2_FIELD_ALTERNATE; @@ -1662,7 +1658,7 @@ int vivid_vid_cap_s_dv_timings(struct file *file, void *_fh, !valid_cvt_gtf_timings(timings)) return -EINVAL; - if (v4l2_match_dv_timings(timings, &dev->dv_timings_cap, 0)) + if (v4l2_match_dv_timings(timings, &dev->dv_timings_cap, 0, false)) return 0; if (vb2_is_busy(&dev->vb_vid_cap_q)) return -EBUSY; diff --git a/drivers/media/platform/vivid/vivid-vid-out.c b/drivers/media/platform/vivid/vivid-vid-out.c index b77acb6a7..64e4d6648 100644 --- a/drivers/media/platform/vivid/vivid-vid-out.c +++ b/drivers/media/platform/vivid/vivid-vid-out.c @@ -31,11 +31,10 @@ #include "vivid-kthread-out.h" #include "vivid-vid-out.h" -static int vid_out_queue_setup(struct vb2_queue *vq, const void *parg, +static int vid_out_queue_setup(struct vb2_queue *vq, unsigned *nbuffers, unsigned *nplanes, unsigned sizes[], void *alloc_ctxs[]) { - const struct v4l2_format *fmt = parg; struct vivid_dev *dev = vb2_get_drv_priv(vq); const struct vivid_fmt *vfmt = dev->fmt_out; unsigned planes = vfmt->buffers; @@ -64,26 +63,16 @@ static int vid_out_queue_setup(struct vb2_queue *vq, const void *parg, return -EINVAL; } - if (fmt) { - const struct v4l2_pix_format_mplane *mp; - struct v4l2_format mp_fmt; - - if (!V4L2_TYPE_IS_MULTIPLANAR(fmt->type)) { - fmt_sp2mp(fmt, &mp_fmt); - fmt = &mp_fmt; - } - mp = &fmt->fmt.pix_mp; + if (*nplanes) { /* - * Check if the number of planes in the specified format match + * Check if the number of requested planes match * the number of planes in the current format. You can't mix that. */ - if (mp->num_planes != planes) + if (*nplanes != planes) return -EINVAL; - sizes[0] = mp->plane_fmt[0].sizeimage; if (sizes[0] < size) return -EINVAL; for (p = 1; p < planes; p++) { - sizes[p] = mp->plane_fmt[p].sizeimage; if (sizes[p] < dev->bytesperline_out[p] * h) return -EINVAL; } @@ -224,6 +213,7 @@ void vivid_update_format_out(struct vivid_dev *dev) { struct v4l2_bt_timings *bt = &dev->dv_timings_out.bt; unsigned size, p; + u64 pixelclock; switch (dev->output_type[dev->output]) { case SVID: @@ -245,8 +235,14 @@ void vivid_update_format_out(struct vivid_dev *dev) dev->sink_rect.width = bt->width; dev->sink_rect.height = bt->height; size = V4L2_DV_BT_FRAME_WIDTH(bt) * V4L2_DV_BT_FRAME_HEIGHT(bt); + + if (can_reduce_fps(bt) && (bt->flags & V4L2_DV_FL_REDUCED_FPS)) + pixelclock = div_u64(bt->pixelclock * 1000, 1001); + else + pixelclock = bt->pixelclock; + dev->timeperframe_vid_out = (struct v4l2_fract) { - size / 100, (u32)bt->pixelclock / 100 + size / 100, (u32)pixelclock / 100 }; if (bt->interlaced) dev->field_out = V4L2_FIELD_ALTERNATE; @@ -1149,7 +1145,7 @@ int vivid_vid_out_s_dv_timings(struct file *file, void *_fh, 0, NULL, NULL) && !valid_cvt_gtf_timings(timings)) return -EINVAL; - if (v4l2_match_dv_timings(timings, &dev->dv_timings_out, 0)) + if (v4l2_match_dv_timings(timings, &dev->dv_timings_out, 0, true)) return 0; if (vb2_is_busy(&dev->vb_vid_out_q)) return -EBUSY; diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c index 4e6188638..533bc7963 100644 --- a/drivers/media/platform/vsp1/vsp1_drv.c +++ b/drivers/media/platform/vsp1/vsp1_drv.c @@ -101,7 +101,7 @@ static int vsp1_create_links(struct vsp1_device *vsp1, struct vsp1_entity *sink) if (!(entity->pads[pad].flags & MEDIA_PAD_FL_SINK)) continue; - ret = media_entity_create_link(&source->subdev.entity, + ret = media_create_pad_link(&source->subdev.entity, source->source_pad, entity, pad, flags); if (ret < 0) @@ -127,6 +127,7 @@ static void vsp1_destroy_entities(struct vsp1_device *vsp1) v4l2_device_unregister(&vsp1->v4l2_dev); media_device_unregister(&vsp1->media_dev); + media_device_cleanup(&vsp1->media_dev); } static int vsp1_create_entities(struct vsp1_device *vsp1) @@ -141,12 +142,7 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) strlcpy(mdev->model, "VSP1", sizeof(mdev->model)); snprintf(mdev->bus_info, sizeof(mdev->bus_info), "platform:%s", dev_name(mdev->dev)); - ret = media_device_register(mdev); - if (ret < 0) { - dev_err(vsp1->dev, "media device registration failed (%d)\n", - ret); - return ret; - } + media_device_init(mdev); vdev->mdev = mdev; ret = v4l2_device_register(vsp1->dev, vdev); @@ -250,34 +246,47 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) list_add_tail(&wpf->entity.list_dev, &vsp1->entities); } - /* Create links. */ + /* Register all subdevs. */ list_for_each_entry(entity, &vsp1->entities, list_dev) { - if (entity->type == VSP1_ENTITY_LIF || - entity->type == VSP1_ENTITY_RPF) - continue; - - ret = vsp1_create_links(vsp1, entity); + ret = v4l2_device_register_subdev(&vsp1->v4l2_dev, + &entity->subdev); if (ret < 0) goto done; } + /* Create links. */ + list_for_each_entry(entity, &vsp1->entities, list_dev) { + if (entity->type == VSP1_ENTITY_WPF) { + ret = vsp1_wpf_create_links(vsp1, entity); + if (ret < 0) + goto done; + } else if (entity->type == VSP1_ENTITY_RPF) { + ret = vsp1_rpf_create_links(vsp1, entity); + if (ret < 0) + goto done; + } + + if (entity->type != VSP1_ENTITY_LIF && + entity->type != VSP1_ENTITY_RPF) { + ret = vsp1_create_links(vsp1, entity); + if (ret < 0) + goto done; + } + } + if (vsp1->pdata.features & VSP1_HAS_LIF) { - ret = media_entity_create_link( + ret = media_create_pad_link( &vsp1->wpf[0]->entity.subdev.entity, RWPF_PAD_SOURCE, &vsp1->lif->entity.subdev.entity, LIF_PAD_SINK, 0); if (ret < 0) return ret; } - /* Register all subdevs. */ - list_for_each_entry(entity, &vsp1->entities, list_dev) { - ret = v4l2_device_register_subdev(&vsp1->v4l2_dev, - &entity->subdev); - if (ret < 0) - goto done; - } - ret = v4l2_device_register_subdev_nodes(&vsp1->v4l2_dev); + if (ret < 0) + goto done; + + ret = media_device_register(mdev); done: if (ret < 0) diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c index fd95a75b0..d73085309 100644 --- a/drivers/media/platform/vsp1/vsp1_entity.c +++ b/drivers/media/platform/vsp1/vsp1_entity.c @@ -219,8 +219,8 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity, entity->pads[num_pads - 1].flags = MEDIA_PAD_FL_SOURCE; /* Initialize the media entity. */ - return media_entity_init(&entity->subdev.entity, num_pads, - entity->pads, 0); + return media_entity_pads_init(&entity->subdev.entity, num_pads, + entity->pads); } void vsp1_entity_destroy(struct vsp1_entity *entity) diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c index cd5248a9a..924538223 100644 --- a/drivers/media/platform/vsp1/vsp1_rpf.c +++ b/drivers/media/platform/vsp1/vsp1_rpf.c @@ -277,18 +277,29 @@ struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index) rpf->entity.video = video; - /* Connect the video device to the RPF. */ - ret = media_entity_create_link(&rpf->video.video.entity, 0, - &rpf->entity.subdev.entity, - RWPF_PAD_SINK, - MEDIA_LNK_FL_ENABLED | - MEDIA_LNK_FL_IMMUTABLE); - if (ret < 0) - goto error; - return rpf; error: vsp1_entity_destroy(&rpf->entity); return ERR_PTR(ret); } + +/* + * vsp1_rpf_create_links() - RPF pads links creation + * @vsp1: Pointer to VSP1 device + * @entity: Pointer to VSP1 entity + * + * return negative error code or zero on success + */ +int vsp1_rpf_create_links(struct vsp1_device *vsp1, + struct vsp1_entity *entity) +{ + struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev); + + /* Connect the video device to the RPF. */ + return media_create_pad_link(&rpf->video.video.entity, 0, + &rpf->entity.subdev.entity, + RWPF_PAD_SINK, + MEDIA_LNK_FL_ENABLED | + MEDIA_LNK_FL_IMMUTABLE); +} diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h index f452dce1a..731d36e52 100644 --- a/drivers/media/platform/vsp1/vsp1_rwpf.h +++ b/drivers/media/platform/vsp1/vsp1_rwpf.h @@ -50,6 +50,11 @@ static inline struct vsp1_rwpf *to_rwpf(struct v4l2_subdev *subdev) struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index); struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index); +int vsp1_rpf_create_links(struct vsp1_device *vsp1, + struct vsp1_entity *entity); +int vsp1_wpf_create_links(struct vsp1_device *vsp1, + struct vsp1_entity *entity); + int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code); diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c index 5ce88e1f5..b4dca57d1 100644 --- a/drivers/media/platform/vsp1/vsp1_video.c +++ b/drivers/media/platform/vsp1/vsp1_video.c @@ -160,8 +160,7 @@ vsp1_video_remote_subdev(struct media_pad *local, u32 *pad) struct media_pad *remote; remote = media_entity_remote_pad(local); - if (remote == NULL || - media_entity_type(remote->entity) != MEDIA_ENT_T_V4L2_SUBDEV) + if (!remote || !is_media_entity_v4l2_subdev(remote->entity)) return NULL; if (pad) @@ -274,35 +273,6 @@ static int __vsp1_video_try_format(struct vsp1_video *video, return 0; } -static bool -vsp1_video_format_adjust(struct vsp1_video *video, - const struct v4l2_pix_format_mplane *format, - struct v4l2_pix_format_mplane *adjust) -{ - unsigned int i; - - *adjust = *format; - __vsp1_video_try_format(video, adjust, NULL); - - if (format->width != adjust->width || - format->height != adjust->height || - format->pixelformat != adjust->pixelformat || - format->num_planes != adjust->num_planes) - return false; - - for (i = 0; i < format->num_planes; ++i) { - if (format->plane_fmt[i].bytesperline != - adjust->plane_fmt[i].bytesperline) - return false; - - adjust->plane_fmt[i].sizeimage = - max(adjust->plane_fmt[i].sizeimage, - format->plane_fmt[i].sizeimage); - } - - return true; -} - /* ----------------------------------------------------------------------------- * Pipeline Management */ @@ -312,24 +282,35 @@ static int vsp1_pipeline_validate_branch(struct vsp1_pipeline *pipe, struct vsp1_rwpf *output) { struct vsp1_entity *entity; - unsigned int entities = 0; + struct media_entity_enum ent_enum; struct media_pad *pad; + int rval; bool bru_found = false; input->location.left = 0; input->location.top = 0; + rval = media_entity_enum_init( + &ent_enum, input->entity.pads[RWPF_PAD_SOURCE].graph_obj.mdev); + if (rval) + return rval; + pad = media_entity_remote_pad(&input->entity.pads[RWPF_PAD_SOURCE]); while (1) { - if (pad == NULL) - return -EPIPE; + if (pad == NULL) { + rval = -EPIPE; + goto out; + } /* We've reached a video node, that shouldn't have happened. */ - if (media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) - return -EPIPE; + if (!is_media_entity_v4l2_subdev(pad->entity)) { + rval = -EPIPE; + goto out; + } - entity = to_vsp1_entity(media_entity_to_v4l2_subdev(pad->entity)); + entity = to_vsp1_entity( + media_entity_to_v4l2_subdev(pad->entity)); /* A BRU is present in the pipeline, store the compose rectangle * location in the input RPF for use when configuring the RPF. @@ -352,15 +333,18 @@ static int vsp1_pipeline_validate_branch(struct vsp1_pipeline *pipe, break; /* Ensure the branch has no loop. */ - if (entities & (1 << entity->subdev.entity.id)) - return -EPIPE; - - entities |= 1 << entity->subdev.entity.id; + if (media_entity_enum_test_and_set(&ent_enum, + &entity->subdev.entity)) { + rval = -EPIPE; + goto out; + } /* UDS can't be chained. */ if (entity->type == VSP1_ENTITY_UDS) { - if (pipe->uds) - return -EPIPE; + if (pipe->uds) { + rval = -EPIPE; + goto out; + } pipe->uds = entity; pipe->uds_input = bru_found ? pipe->bru @@ -378,9 +362,12 @@ static int vsp1_pipeline_validate_branch(struct vsp1_pipeline *pipe, /* The last entity must be the output WPF. */ if (entity != &output->entity) - return -EPIPE; + rval = -EPIPE; - return 0; +out: + media_entity_enum_cleanup(&ent_enum); + + return rval; } static void __vsp1_pipeline_cleanup(struct vsp1_pipeline *pipe) @@ -409,13 +396,19 @@ static int vsp1_pipeline_validate(struct vsp1_pipeline *pipe, { struct media_entity_graph graph; struct media_entity *entity = &video->video.entity; - struct media_device *mdev = entity->parent; + struct media_device *mdev = entity->graph_obj.mdev; unsigned int i; int ret; mutex_lock(&mdev->graph_mutex); /* Walk the graph to locate the entities and video nodes. */ + ret = media_entity_graph_walk_init(&graph, mdev); + if (ret) { + mutex_unlock(&mdev->graph_mutex); + return ret; + } + media_entity_graph_walk_start(&graph, entity); while ((entity = media_entity_graph_walk_next(&graph))) { @@ -423,7 +416,7 @@ static int vsp1_pipeline_validate(struct vsp1_pipeline *pipe, struct vsp1_rwpf *rwpf; struct vsp1_entity *e; - if (media_entity_type(entity) != MEDIA_ENT_T_V4L2_SUBDEV) { + if (is_media_entity_v4l2_io(entity)) { pipe->num_video++; continue; } @@ -449,6 +442,8 @@ static int vsp1_pipeline_validate(struct vsp1_pipeline *pipe, mutex_unlock(&mdev->graph_mutex); + media_entity_graph_walk_cleanup(&graph); + /* We need one output and at least one input. */ if (pipe->num_inputs == 0 || !pipe->output) { ret = -EPIPE; @@ -520,7 +515,7 @@ static bool vsp1_pipeline_stopped(struct vsp1_pipeline *pipe) bool stopped; spin_lock_irqsave(&pipe->irqlock, flags); - stopped = pipe->state == VSP1_PIPELINE_STOPPED, + stopped = pipe->state == VSP1_PIPELINE_STOPPED; spin_unlock_irqrestore(&pipe->irqlock, flags); return stopped; @@ -611,7 +606,7 @@ vsp1_video_complete_buffer(struct vsp1_video *video) spin_unlock_irqrestore(&video->irqlock, flags); done->buf.sequence = video->sequence++; - v4l2_get_timestamp(&done->buf.timestamp); + done->buf.vb2_buf.timestamp = ktime_get_ns(); for (i = 0; i < done->buf.vb2_buf.num_planes; ++i) vb2_set_plane_payload(&done->buf.vb2_buf, i, done->length[i]); vb2_buffer_done(&done->buf.vb2_buf, VB2_BUF_STATE_DONE); @@ -692,7 +687,7 @@ void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe, pad = media_entity_remote_pad(&input->pads[RWPF_PAD_SOURCE]); while (pad) { - if (media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) + if (!is_media_entity_v4l2_subdev(pad->entity)) break; entity = to_vsp1_entity(media_entity_to_v4l2_subdev(pad->entity)); @@ -787,26 +782,24 @@ void vsp1_pipelines_resume(struct vsp1_device *vsp1) */ static int -vsp1_video_queue_setup(struct vb2_queue *vq, const void *parg, +vsp1_video_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) { - const struct v4l2_format *fmt = parg; struct vsp1_video *video = vb2_get_drv_priv(vq); - const struct v4l2_pix_format_mplane *format; - struct v4l2_pix_format_mplane pix_mp; + const struct v4l2_pix_format_mplane *format = &video->format; unsigned int i; - if (fmt) { - /* Make sure the format is valid and adjust the sizeimage field - * if needed. - */ - if (!vsp1_video_format_adjust(video, &fmt->fmt.pix_mp, &pix_mp)) + if (*nplanes) { + if (*nplanes != format->num_planes) return -EINVAL; - format = &pix_mp; - } else { - format = &video->format; + for (i = 0; i < *nplanes; i++) { + if (sizes[i] < format->plane_fmt[i].sizeimage) + return -EINVAL; + alloc_ctxs[i] = video->alloc_ctx; + } + return 0; } *nplanes = format->num_planes; @@ -1224,7 +1217,7 @@ int vsp1_video_init(struct vsp1_video *video, struct vsp1_entity *rwpf) video->pipe.state = VSP1_PIPELINE_STOPPED; /* Initialize the media entity... */ - ret = media_entity_init(&video->video.entity, 1, &video->pad, 0); + ret = media_entity_pads_init(&video->video.entity, 1, &video->pad); if (ret < 0) return ret; diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c index 95b62f4f7..cbf514a65 100644 --- a/drivers/media/platform/vsp1/vsp1_wpf.c +++ b/drivers/media/platform/vsp1/vsp1_wpf.c @@ -220,7 +220,6 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index) struct v4l2_subdev *subdev; struct vsp1_video *video; struct vsp1_rwpf *wpf; - unsigned int flags; int ret; wpf = devm_kzalloc(vsp1->dev, sizeof(*wpf), GFP_KERNEL); @@ -276,20 +275,6 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index) goto error; wpf->entity.video = video; - - /* Connect the video device to the WPF. All connections are immutable - * except for the WPF0 source link if a LIF is present. - */ - flags = MEDIA_LNK_FL_ENABLED; - if (!(vsp1->pdata.features & VSP1_HAS_LIF) || index != 0) - flags |= MEDIA_LNK_FL_IMMUTABLE; - - ret = media_entity_create_link(&wpf->entity.subdev.entity, - RWPF_PAD_SOURCE, - &wpf->video.video.entity, 0, flags); - if (ret < 0) - goto error; - wpf->entity.sink = &wpf->video.video.entity; return wpf; @@ -298,3 +283,28 @@ error: vsp1_entity_destroy(&wpf->entity); return ERR_PTR(ret); } + +/* + * vsp1_wpf_create_links() - RPF pads links creation + * @vsp1: Pointer to VSP1 device + * @entity: Pointer to VSP1 entity + * + * return negative error code or zero on success + */ +int vsp1_wpf_create_links(struct vsp1_device *vsp1, + struct vsp1_entity *entity) +{ + struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev); + unsigned int flags; + + /* Connect the video device to the WPF. All connections are immutable + * except for the WPF0 source link if a LIF is present. + */ + flags = MEDIA_LNK_FL_ENABLED; + if (!(vsp1->pdata.features & VSP1_HAS_LIF) || entity->index != 0) + flags |= MEDIA_LNK_FL_IMMUTABLE; + + return media_create_pad_link(&wpf->entity.subdev.entity, + RWPF_PAD_SOURCE, + &wpf->video.video.entity, 0, flags); +} diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c index d11cc7072..7f6898b13 100644 --- a/drivers/media/platform/xilinx/xilinx-dma.c +++ b/drivers/media/platform/xilinx/xilinx-dma.c @@ -49,8 +49,7 @@ xvip_dma_remote_subdev(struct media_pad *local, u32 *pad) struct media_pad *remote; remote = media_entity_remote_pad(local); - if (remote == NULL || - media_entity_type(remote->entity) != MEDIA_ENT_T_V4L2_SUBDEV) + if (!remote || !is_media_entity_v4l2_subdev(remote->entity)) return NULL; if (pad) @@ -113,8 +112,7 @@ static int xvip_pipeline_start_stop(struct xvip_pipeline *pipe, bool start) break; pad = media_entity_remote_pad(pad); - if (pad == NULL || - media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) + if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) break; entity = pad->entity; @@ -181,19 +179,26 @@ static int xvip_pipeline_validate(struct xvip_pipeline *pipe, { struct media_entity_graph graph; struct media_entity *entity = &start->video.entity; - struct media_device *mdev = entity->parent; + struct media_device *mdev = entity->graph_obj.mdev; unsigned int num_inputs = 0; unsigned int num_outputs = 0; + int ret; mutex_lock(&mdev->graph_mutex); /* Walk the graph to locate the video nodes. */ + ret = media_entity_graph_walk_init(&graph, entity->graph_obj.mdev); + if (ret) { + mutex_unlock(&mdev->graph_mutex); + return ret; + } + media_entity_graph_walk_start(&graph, entity); while ((entity = media_entity_graph_walk_next(&graph))) { struct xvip_dma *dma; - if (entity->type != MEDIA_ENT_T_DEVNODE_V4L) + if (entity->function != MEDIA_ENT_F_IO_V4L) continue; dma = to_xvip_dma(media_entity_to_video_device(entity)); @@ -208,6 +213,8 @@ static int xvip_pipeline_validate(struct xvip_pipeline *pipe, mutex_unlock(&mdev->graph_mutex); + media_entity_graph_walk_cleanup(&graph); + /* We need exactly one output and zero or one input. */ if (num_outputs != 1 || num_inputs > 1) return -EPIPE; @@ -303,27 +310,25 @@ static void xvip_dma_complete(void *param) buf->buf.field = V4L2_FIELD_NONE; buf->buf.sequence = dma->sequence++; - v4l2_get_timestamp(&buf->buf.timestamp); + buf->buf.vb2_buf.timestamp = ktime_get_ns(); vb2_set_plane_payload(&buf->buf.vb2_buf, 0, dma->format.sizeimage); vb2_buffer_done(&buf->buf.vb2_buf, VB2_BUF_STATE_DONE); } static int -xvip_dma_queue_setup(struct vb2_queue *vq, const void *parg, +xvip_dma_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) { - const struct v4l2_format *fmt = parg; struct xvip_dma *dma = vb2_get_drv_priv(vq); + alloc_ctxs[0] = dma->alloc_ctx; /* Make sure the image size is large enough. */ - if (fmt && fmt->fmt.pix.sizeimage < dma->format.sizeimage) - return -EINVAL; + if (*nplanes) + return sizes[0] < dma->format.sizeimage ? -EINVAL : 0; *nplanes = 1; - - sizes[0] = fmt ? fmt->fmt.pix.sizeimage : dma->format.sizeimage; - alloc_ctxs[0] = dma->alloc_ctx; + sizes[0] = dma->format.sizeimage; return 0; } @@ -679,7 +684,7 @@ int xvip_dma_init(struct xvip_composite_device *xdev, struct xvip_dma *dma, dma->pad.flags = type == V4L2_BUF_TYPE_VIDEO_CAPTURE ? MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE; - ret = media_entity_init(&dma->video.entity, 1, &dma->pad, 0); + ret = media_entity_pads_init(&dma->video.entity, 1, &dma->pad); if (ret < 0) goto error; diff --git a/drivers/media/platform/xilinx/xilinx-tpg.c b/drivers/media/platform/xilinx/xilinx-tpg.c index b5f7d5ecb..2ec1f6c4b 100644 --- a/drivers/media/platform/xilinx/xilinx-tpg.c +++ b/drivers/media/platform/xilinx/xilinx-tpg.c @@ -731,6 +731,7 @@ static int xtpg_parse_of(struct xtpg_device *xtpg) format = xvip_of_get_format(port); if (IS_ERR(format)) { dev_err(dev, "invalid format in DT"); + of_node_put(port); return PTR_ERR(format); } @@ -739,6 +740,7 @@ static int xtpg_parse_of(struct xtpg_device *xtpg) xtpg->vip_format = format; } else if (xtpg->vip_format != format) { dev_err(dev, "in/out format mismatch in DT"); + of_node_put(port); return -EINVAL; } @@ -836,7 +838,7 @@ static int xtpg_probe(struct platform_device *pdev) subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; subdev->entity.ops = &xtpg_media_ops; - ret = media_entity_init(&subdev->entity, xtpg->npads, xtpg->pads, 0); + ret = media_entity_pads_init(&subdev->entity, xtpg->npads, xtpg->pads); if (ret < 0) goto error; diff --git a/drivers/media/platform/xilinx/xilinx-vipp.c b/drivers/media/platform/xilinx/xilinx-vipp.c index 7b7cb9c28..e795a4501 100644 --- a/drivers/media/platform/xilinx/xilinx-vipp.c +++ b/drivers/media/platform/xilinx/xilinx-vipp.c @@ -156,7 +156,7 @@ static int xvip_graph_build_one(struct xvip_composite_device *xdev, local->name, local_pad->index, remote->name, remote_pad->index); - ret = media_entity_create_link(local, local_pad->index, + ret = media_create_pad_link(local, local_pad->index, remote, remote_pad->index, link_flags); if (ret < 0) { @@ -270,7 +270,7 @@ static int xvip_graph_build_dma(struct xvip_composite_device *xdev) source->name, source_pad->index, sink->name, sink_pad->index); - ret = media_entity_create_link(source, source_pad->index, + ret = media_create_pad_link(source, source_pad->index, sink, sink_pad->index, link_flags); if (ret < 0) { @@ -311,7 +311,7 @@ static int xvip_graph_notify_complete(struct v4l2_async_notifier *notifier) if (ret < 0) dev_err(xdev->dev, "failed to register subdev nodes\n"); - return ret; + return media_device_register(&xdev->media_dev); } static int xvip_graph_notify_bound(struct v4l2_async_notifier *notifier, @@ -476,8 +476,10 @@ static int xvip_graph_dma_init(struct xvip_composite_device *xdev) for_each_child_of_node(ports, port) { ret = xvip_graph_dma_init_one(xdev, port); - if (ret < 0) + if (ret < 0) { + of_node_put(port); return ret; + } } return 0; @@ -571,6 +573,7 @@ static void xvip_composite_v4l2_cleanup(struct xvip_composite_device *xdev) { v4l2_device_unregister(&xdev->v4l2_dev); media_device_unregister(&xdev->media_dev); + media_device_cleanup(&xdev->media_dev); } static int xvip_composite_v4l2_init(struct xvip_composite_device *xdev) @@ -582,19 +585,14 @@ static int xvip_composite_v4l2_init(struct xvip_composite_device *xdev) sizeof(xdev->media_dev.model)); xdev->media_dev.hw_revision = 0; - ret = media_device_register(&xdev->media_dev); - if (ret < 0) { - dev_err(xdev->dev, "media device registration failed (%d)\n", - ret); - return ret; - } + media_device_init(&xdev->media_dev); xdev->v4l2_dev.mdev = &xdev->media_dev; ret = v4l2_device_register(xdev->dev, &xdev->v4l2_dev); if (ret < 0) { dev_err(xdev->dev, "V4L2 device registration failed (%d)\n", ret); - media_device_unregister(&xdev->media_dev); + media_device_cleanup(&xdev->media_dev); return ret; } diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c index 5236035f0..70fd8e801 100644 --- a/drivers/media/radio/radio-maxiradio.c +++ b/drivers/media/radio/radio-maxiradio.c @@ -42,7 +42,7 @@ #include <linux/videodev2.h> #include <linux/io.h> #include <linux/slab.h> -#include <media/tea575x.h> +#include <media/drv-intf/tea575x.h> #include <media/v4l2-device.h> #include <media/v4l2-ioctl.h> #include <media/v4l2-fh.h> @@ -108,7 +108,7 @@ static void maxiradio_tea575x_set_direction(struct snd_tea575x *tea, bool output { } -static struct snd_tea575x_ops maxiradio_tea_ops = { +static const struct snd_tea575x_ops maxiradio_tea_ops = { .set_pins = maxiradio_tea575x_set_pins, .get_pins = maxiradio_tea575x_get_pins, .set_direction = maxiradio_tea575x_set_direction, diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c index b8d61cbc1..dc81d422b 100644 --- a/drivers/media/radio/radio-sf16fmr2.c +++ b/drivers/media/radio/radio-sf16fmr2.c @@ -14,7 +14,7 @@ #include <linux/io.h> /* outb, outb_p */ #include <linux/isa.h> #include <linux/pnp.h> -#include <media/tea575x.h> +#include <media/drv-intf/tea575x.h> MODULE_AUTHOR("Ondrej Zary"); MODULE_DESCRIPTION("MediaForte SF16-FMR2 and SF16-FMD2 FM radio card driver"); @@ -82,7 +82,7 @@ static void fmr2_tea575x_set_direction(struct snd_tea575x *tea, bool output) { } -static struct snd_tea575x_ops fmr2_tea_ops = { +static const struct snd_tea575x_ops fmr2_tea_ops = { .set_pins = fmr2_tea575x_set_pins, .get_pins = fmr2_tea575x_get_pins, .set_direction = fmr2_tea575x_set_direction, diff --git a/drivers/media/radio/radio-shark.c b/drivers/media/radio/radio-shark.c index 050b3bb96..85667a95f 100644 --- a/drivers/media/radio/radio-shark.c +++ b/drivers/media/radio/radio-shark.c @@ -33,7 +33,7 @@ #include <linux/usb.h> #include <linux/workqueue.h> #include <media/v4l2-device.h> -#include <media/tea575x.h> +#include <media/drv-intf/tea575x.h> #if defined(CONFIG_LEDS_CLASS) || \ (defined(CONFIG_LEDS_CLASS_MODULE) && defined(CONFIG_RADIO_SHARK_MODULE)) @@ -150,7 +150,7 @@ static u32 shark_read_val(struct snd_tea575x *tea) return val; } -static struct snd_tea575x_ops shark_tea_ops = { +static const struct snd_tea575x_ops shark_tea_ops = { .write_val = shark_write_val, .read_val = shark_read_val, }; diff --git a/drivers/media/radio/radio-shark2.c b/drivers/media/radio/radio-shark2.c index 8654e0dc5..0e65a85d5 100644 --- a/drivers/media/radio/radio-shark2.c +++ b/drivers/media/radio/radio-shark2.c @@ -137,7 +137,7 @@ static int shark_read_reg(struct radio_tea5777 *tea, u32 *reg_ret) return 0; } -static struct radio_tea5777_ops shark_tea_ops = { +static const struct radio_tea5777_ops shark_tea_ops = { .write_reg = shark_write_reg, .read_reg = shark_read_reg, }; diff --git a/drivers/media/radio/radio-si476x.c b/drivers/media/radio/radio-si476x.c index 9cbb8cdf0..859f0c08e 100644 --- a/drivers/media/radio/radio-si476x.c +++ b/drivers/media/radio/radio-si476x.c @@ -31,7 +31,7 @@ #include <media/v4l2-event.h> #include <media/v4l2-device.h> -#include <media/si476x.h> +#include <media/drv-intf/si476x.h> #include <linux/mfd/si476x-core.h> #define FM_FREQ_RANGE_LOW 64000000 diff --git a/drivers/media/radio/radio-tea5777.h b/drivers/media/radio/radio-tea5777.h index 4ea43a90a..4bd942526 100644 --- a/drivers/media/radio/radio-tea5777.h +++ b/drivers/media/radio/radio-tea5777.h @@ -76,7 +76,7 @@ struct radio_tea5777 { u32 read_reg; u64 write_reg; struct mutex mutex; - struct radio_tea5777_ops *ops; + const struct radio_tea5777_ops *ops; void *private_data; u8 card[32]; u8 bus_info[32]; diff --git a/drivers/media/radio/radio-timb.c b/drivers/media/radio/radio-timb.c index 04baafe5e..a82eb9678 100644 --- a/drivers/media/radio/radio-timb.c +++ b/drivers/media/radio/radio-timb.c @@ -26,7 +26,7 @@ #include <linux/slab.h> #include <linux/i2c.h> #include <linux/module.h> -#include <media/timb_radio.h> +#include <linux/platform_data/media/timb_radio.h> #define DRIVER_NAME "timb-radio" diff --git a/drivers/media/radio/si4713/radio-usb-si4713.c b/drivers/media/radio/si4713/radio-usb-si4713.c index a77319dcb..5146be2a1 100644 --- a/drivers/media/radio/si4713/radio-usb-si4713.c +++ b/drivers/media/radio/si4713/radio-usb-si4713.c @@ -31,7 +31,7 @@ #include <media/v4l2-device.h> #include <media/v4l2-ioctl.h> #include <media/v4l2-event.h> -#include <media/si4713.h> +#include <linux/platform_data/media/si4713.h> #include "si4713.h" diff --git a/drivers/media/radio/si4713/si4713.h b/drivers/media/radio/si4713/si4713.h index 8a376e142..29d0e1f10 100644 --- a/drivers/media/radio/si4713/si4713.h +++ b/drivers/media/radio/si4713/si4713.h @@ -20,7 +20,7 @@ #include <linux/gpio/consumer.h> #include <media/v4l2-subdev.h> #include <media/v4l2-ctrls.h> -#include <media/si4713.h> +#include <linux/platform_data/media/si4713.h> #define SI4713_PRODUCT_NUMBER 0x0D diff --git a/drivers/media/radio/tea575x.c b/drivers/media/radio/tea575x.c index 43d1ea53c..3e08475af 100644 --- a/drivers/media/radio/tea575x.c +++ b/drivers/media/radio/tea575x.c @@ -31,7 +31,7 @@ #include <media/v4l2-fh.h> #include <media/v4l2-ioctl.h> #include <media/v4l2-event.h> -#include <media/tea575x.h> +#include <media/drv-intf/tea575x.h> MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("Routines for control of TEA5757/5759 Philips AM/FM radio tuner chips"); diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index b6e13116c..bd4d68500 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -101,7 +101,8 @@ config IR_SHARP_DECODER ---help--- Enable this option if you have an infrared remote control which - uses the Sharp protocol, and you need software decoding support. + uses the Sharp protocol (Sharp, Denon), and you need software + decoding support. config IR_MCE_KBD_DECODER tristate "Enable IR raw decoder for the MCE keyboard/mouse protocol" diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c index 7dbc9ca6d..5b63b1f15 100644 --- a/drivers/media/rc/gpio-ir-recv.c +++ b/drivers/media/rc/gpio-ir-recv.c @@ -21,7 +21,7 @@ #include <linux/platform_device.h> #include <linux/irq.h> #include <media/rc-core.h> -#include <media/gpio-ir-recv.h> +#include <linux/platform_data/media/gpio-ir-recv.h> #define GPIO_IR_DRIVER_NAME "gpio-rc-recv" #define GPIO_IR_DEVICE_NAME "gpio_ir_recv" @@ -30,6 +30,7 @@ struct gpio_rc_dev { struct rc_dev *rcdev; int gpio_nr; bool active_low; + struct timer_list flush_timer; }; #ifdef CONFIG_OF @@ -93,12 +94,26 @@ static irqreturn_t gpio_ir_recv_irq(int irq, void *dev_id) if (rc < 0) goto err_get_value; + mod_timer(&gpio_dev->flush_timer, + jiffies + nsecs_to_jiffies(gpio_dev->rcdev->timeout)); + ir_raw_event_handle(gpio_dev->rcdev); err_get_value: return IRQ_HANDLED; } +static void flush_timer(unsigned long arg) +{ + struct gpio_rc_dev *gpio_dev = (struct gpio_rc_dev *)arg; + DEFINE_IR_RAW_EVENT(ev); + + ev.timeout = true; + ev.duration = gpio_dev->rcdev->timeout; + ir_raw_event_store(gpio_dev->rcdev, &ev); + ir_raw_event_handle(gpio_dev->rcdev); +} + static int gpio_ir_recv_probe(struct platform_device *pdev) { struct gpio_rc_dev *gpio_dev; @@ -144,6 +159,9 @@ static int gpio_ir_recv_probe(struct platform_device *pdev) rcdev->input_id.version = 0x0100; rcdev->dev.parent = &pdev->dev; rcdev->driver_name = GPIO_IR_DRIVER_NAME; + rcdev->min_timeout = 0; + rcdev->timeout = IR_DEFAULT_TIMEOUT; + rcdev->max_timeout = 10 * IR_DEFAULT_TIMEOUT; if (pdata->allowed_protos) rcdev->allowed_protocols = pdata->allowed_protos; else @@ -154,6 +172,9 @@ static int gpio_ir_recv_probe(struct platform_device *pdev) gpio_dev->gpio_nr = pdata->gpio_nr; gpio_dev->active_low = pdata->active_low; + setup_timer(&gpio_dev->flush_timer, flush_timer, + (unsigned long)gpio_dev); + rc = gpio_request(pdata->gpio_nr, "gpio-ir-recv"); if (rc < 0) goto err_gpio_request; @@ -196,6 +217,7 @@ static int gpio_ir_recv_remove(struct platform_device *pdev) struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev); free_irq(gpio_to_irq(gpio_dev->gpio_nr), gpio_dev); + del_timer_sync(&gpio_dev->flush_timer); rc_unregister_device(gpio_dev->rcdev); gpio_free(gpio_dev->gpio_nr); kfree(gpio_dev); diff --git a/drivers/media/rc/ir-jvc-decoder.c b/drivers/media/rc/ir-jvc-decoder.c index 30bcf188d..182402f7b 100644 --- a/drivers/media/rc/ir-jvc-decoder.c +++ b/drivers/media/rc/ir-jvc-decoder.c @@ -47,9 +47,6 @@ static int ir_jvc_decode(struct rc_dev *dev, struct ir_raw_event ev) { struct jvc_dec *data = &dev->raw->jvc; - if (!(dev->enabled_protocols & RC_BIT_JVC)) - return 0; - if (!is_timing_event(ev)) { if (ev.reset) data->state = STATE_INACTIVE; diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index a32659fcd..5effc65d2 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c @@ -415,6 +415,7 @@ static int ir_lirc_unregister(struct rc_dev *dev) lirc_unregister_driver(lirc->drv->minor); lirc_buffer_free(lirc->drv->rbuf); + kfree(lirc->drv->rbuf); kfree(lirc->drv); return 0; diff --git a/drivers/media/rc/ir-mce_kbd-decoder.c b/drivers/media/rc/ir-mce_kbd-decoder.c index 9f3c9b59f..d80986251 100644 --- a/drivers/media/rc/ir-mce_kbd-decoder.c +++ b/drivers/media/rc/ir-mce_kbd-decoder.c @@ -216,9 +216,6 @@ static int ir_mce_kbd_decode(struct rc_dev *dev, struct ir_raw_event ev) u32 scancode; unsigned long delay; - if (!(dev->enabled_protocols & RC_BIT_MCE_KBD)) - return 0; - if (!is_timing_event(ev)) { if (ev.reset) data->state = STATE_INACTIVE; diff --git a/drivers/media/rc/ir-nec-decoder.c b/drivers/media/rc/ir-nec-decoder.c index 7b81fec08..bea0d1eed 100644 --- a/drivers/media/rc/ir-nec-decoder.c +++ b/drivers/media/rc/ir-nec-decoder.c @@ -52,9 +52,6 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev) u8 address, not_address, command, not_command; bool send_32bits = false; - if (!(dev->enabled_protocols & RC_BIT_NEC)) - return 0; - if (!is_timing_event(ev)) { if (ev.reset) data->state = STATE_INACTIVE; diff --git a/drivers/media/rc/ir-rc5-decoder.c b/drivers/media/rc/ir-rc5-decoder.c index 84fa6e9b5..6ffe776ab 100644 --- a/drivers/media/rc/ir-rc5-decoder.c +++ b/drivers/media/rc/ir-rc5-decoder.c @@ -53,9 +53,6 @@ static int ir_rc5_decode(struct rc_dev *dev, struct ir_raw_event ev) u32 scancode; enum rc_type protocol; - if (!(dev->enabled_protocols & (RC_BIT_RC5 | RC_BIT_RC5X | RC_BIT_RC5_SZ))) - return 0; - if (!is_timing_event(ev)) { if (ev.reset) data->state = STATE_INACTIVE; diff --git a/drivers/media/rc/ir-rc6-decoder.c b/drivers/media/rc/ir-rc6-decoder.c index d16bc67af..e0e2edefa 100644 --- a/drivers/media/rc/ir-rc6-decoder.c +++ b/drivers/media/rc/ir-rc6-decoder.c @@ -90,11 +90,6 @@ static int ir_rc6_decode(struct rc_dev *dev, struct ir_raw_event ev) u8 toggle; enum rc_type protocol; - if (!(dev->enabled_protocols & - (RC_BIT_RC6_0 | RC_BIT_RC6_6A_20 | RC_BIT_RC6_6A_24 | - RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE))) - return 0; - if (!is_timing_event(ev)) { if (ev.reset) data->state = STATE_INACTIVE; diff --git a/drivers/media/rc/ir-rx51.c b/drivers/media/rc/ir-rx51.c index b1e19a262..4e1711a40 100644 --- a/drivers/media/rc/ir-rx51.c +++ b/drivers/media/rc/ir-rx51.c @@ -31,7 +31,7 @@ #include <media/lirc.h> #include <media/lirc_dev.h> -#include <media/ir-rx51.h> +#include <linux/platform_data/media/ir-rx51.h> #define LIRC_RX51_DRIVER_FEATURES (LIRC_CAN_SET_SEND_DUTY_CYCLE | \ LIRC_CAN_SET_SEND_CARRIER | \ diff --git a/drivers/media/rc/ir-sanyo-decoder.c b/drivers/media/rc/ir-sanyo-decoder.c index ad1dc6ae2..7331e5e7c 100644 --- a/drivers/media/rc/ir-sanyo-decoder.c +++ b/drivers/media/rc/ir-sanyo-decoder.c @@ -58,9 +58,6 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev) u32 scancode; u8 address, command, not_command; - if (!(dev->enabled_protocols & RC_BIT_SANYO)) - return 0; - if (!is_timing_event(ev)) { if (ev.reset) { IR_dprintk(1, "SANYO event reset received. reset to state 0\n"); diff --git a/drivers/media/rc/ir-sharp-decoder.c b/drivers/media/rc/ir-sharp-decoder.c index b7acdbae8..317677f06 100644 --- a/drivers/media/rc/ir-sharp-decoder.c +++ b/drivers/media/rc/ir-sharp-decoder.c @@ -48,9 +48,6 @@ static int ir_sharp_decode(struct rc_dev *dev, struct ir_raw_event ev) struct sharp_dec *data = &dev->raw->sharp; u32 msg, echo, address, command, scancode; - if (!(dev->enabled_protocols & RC_BIT_SHARP)) - return 0; - if (!is_timing_event(ev)) { if (ev.reset) data->state = STATE_INACTIVE; @@ -118,7 +115,9 @@ static int ir_sharp_decode(struct rc_dev *dev, struct ir_raw_event ev) if (data->count == SHARP_NBITS) { /* exp,chk bits should be 1,0 */ - if ((data->bits & 0x3) != 0x2) + if ((data->bits & 0x3) != 0x2 && + /* DENON variant, both chk bits 0 */ + (data->bits & 0x3) != 0x0) break; data->state = STATE_ECHO_SPACE; } else { diff --git a/drivers/media/rc/ir-sony-decoder.c b/drivers/media/rc/ir-sony-decoder.c index 58ef06f35..baa972c76 100644 --- a/drivers/media/rc/ir-sony-decoder.c +++ b/drivers/media/rc/ir-sony-decoder.c @@ -46,10 +46,6 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev) u32 scancode; u8 device, subdevice, function; - if (!(dev->enabled_protocols & - (RC_BIT_SONY12 | RC_BIT_SONY15 | RC_BIT_SONY20))) - return 0; - if (!is_timing_event(ev)) { if (ev.reset) data->state = STATE_INACTIVE; diff --git a/drivers/media/rc/ir-xmp-decoder.c b/drivers/media/rc/ir-xmp-decoder.c index 1017d4816..18596190b 100644 --- a/drivers/media/rc/ir-xmp-decoder.c +++ b/drivers/media/rc/ir-xmp-decoder.c @@ -43,9 +43,6 @@ static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev) { struct xmp_dec *data = &dev->raw->xmp; - if (!(dev->enabled_protocols & RC_BIT_XMP)) - return 0; - if (!is_timing_event(ev)) { if (ev.reset) data->state = STATE_INACTIVE; diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c index 85af7a869..18adf580f 100644 --- a/drivers/media/rc/nuvoton-cir.c +++ b/drivers/media/rc/nuvoton-cir.c @@ -39,6 +39,18 @@ #include "nuvoton-cir.h" +static const struct nvt_chip nvt_chips[] = { + { "w83667hg", NVT_W83667HG }, + { "NCT6775F", NVT_6775F }, + { "NCT6776F", NVT_6776F }, + { "NCT6779D", NVT_6779D }, +}; + +static inline bool is_w83667hg(struct nvt_dev *nvt) +{ + return nvt->chip_ver == NVT_W83667HG; +} + /* write val to config reg */ static inline void nvt_cr_write(struct nvt_dev *nvt, u8 val, u8 reg) { @@ -224,74 +236,60 @@ static void cir_wake_dump_regs(struct nvt_dev *nvt) pr_cont("\n"); } +static inline const char *nvt_find_chip(struct nvt_dev *nvt, int id) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(nvt_chips); i++) + if ((id & SIO_ID_MASK) == nvt_chips[i].chip_ver) { + nvt->chip_ver = nvt_chips[i].chip_ver; + return nvt_chips[i].name; + } + + return NULL; +} + + /* detect hardware features */ -static int nvt_hw_detect(struct nvt_dev *nvt) +static void nvt_hw_detect(struct nvt_dev *nvt) { - unsigned long flags; - u8 chip_major, chip_minor; - char chip_id[12]; - bool chip_unknown = false; + const char *chip_name; + int chip_id; nvt_efm_enable(nvt); /* Check if we're wired for the alternate EFER setup */ - chip_major = nvt_cr_read(nvt, CR_CHIP_ID_HI); - if (chip_major == 0xff) { + nvt->chip_major = nvt_cr_read(nvt, CR_CHIP_ID_HI); + if (nvt->chip_major == 0xff) { nvt->cr_efir = CR_EFIR2; nvt->cr_efdr = CR_EFDR2; nvt_efm_enable(nvt); - chip_major = nvt_cr_read(nvt, CR_CHIP_ID_HI); + nvt->chip_major = nvt_cr_read(nvt, CR_CHIP_ID_HI); } - chip_minor = nvt_cr_read(nvt, CR_CHIP_ID_LO); - - /* these are the known working chip revisions... */ - switch (chip_major) { - case CHIP_ID_HIGH_667: - strcpy(chip_id, "w83667hg\0"); - if (chip_minor != CHIP_ID_LOW_667) - chip_unknown = true; - break; - case CHIP_ID_HIGH_677B: - strcpy(chip_id, "w83677hg\0"); - if (chip_minor != CHIP_ID_LOW_677B2 && - chip_minor != CHIP_ID_LOW_677B3) - chip_unknown = true; - break; - case CHIP_ID_HIGH_677C: - strcpy(chip_id, "w83677hg-c\0"); - if (chip_minor != CHIP_ID_LOW_677C) - chip_unknown = true; - break; - default: - strcpy(chip_id, "w836x7hg\0"); - chip_unknown = true; - break; - } + nvt->chip_minor = nvt_cr_read(nvt, CR_CHIP_ID_LO); + + chip_id = nvt->chip_major << 8 | nvt->chip_minor; + chip_name = nvt_find_chip(nvt, chip_id); /* warn, but still let the driver load, if we don't know this chip */ - if (chip_unknown) - nvt_pr(KERN_WARNING, "%s: unknown chip, id: 0x%02x 0x%02x, " - "it may not work...", chip_id, chip_major, chip_minor); + if (!chip_name) + dev_warn(&nvt->pdev->dev, + "unknown chip, id: 0x%02x 0x%02x, it may not work...", + nvt->chip_major, nvt->chip_minor); else - nvt_dbg("%s: chip id: 0x%02x 0x%02x", - chip_id, chip_major, chip_minor); + dev_info(&nvt->pdev->dev, + "found %s or compatible: chip id: 0x%02x 0x%02x", + chip_name, nvt->chip_major, nvt->chip_minor); nvt_efm_disable(nvt); - - spin_lock_irqsave(&nvt->nvt_lock, flags); - nvt->chip_major = chip_major; - nvt->chip_minor = chip_minor; - spin_unlock_irqrestore(&nvt->nvt_lock, flags); - - return 0; } static void nvt_cir_ldev_init(struct nvt_dev *nvt) { u8 val, psreg, psmask, psval; - if (nvt->chip_major == CHIP_ID_HIGH_667) { + if (is_w83667hg(nvt)) { psreg = CR_MULTIFUNC_PIN_SEL; psmask = MULTIFUNC_PIN_SEL_MASK; psval = MULTIFUNC_ENABLE_CIR | MULTIFUNC_ENABLE_CIRWB; @@ -485,8 +483,9 @@ static u32 nvt_rx_carrier_detect(struct nvt_dev *nvt) duration *= SAMPLE_PERIOD; if (!count || !duration) { - nvt_pr(KERN_NOTICE, "Unable to determine carrier! (c:%u, d:%u)", - count, duration); + dev_notice(&nvt->pdev->dev, + "Unable to determine carrier! (c:%u, d:%u)", + count, duration); return 0; } @@ -661,7 +660,7 @@ static void nvt_process_rx_ir_data(struct nvt_dev *nvt) static void nvt_handle_rx_fifo_overrun(struct nvt_dev *nvt) { - nvt_pr(KERN_WARNING, "RX FIFO overrun detected, flushing data!"); + dev_warn(&nvt->pdev->dev, "RX FIFO overrun detected, flushing data!"); nvt->pkts = 0; nvt_clear_cir_fifo(nvt); @@ -719,7 +718,7 @@ static void nvt_get_rx_ir_data(struct nvt_dev *nvt) static void nvt_cir_log_irqs(u8 status, u8 iren) { - nvt_pr(KERN_INFO, "IRQ 0x%02x (IREN 0x%02x) :%s%s%s%s%s%s%s%s%s", + nvt_dbg("IRQ 0x%02x (IREN 0x%02x) :%s%s%s%s%s%s%s%s%s", status, iren, status & CIR_IRSTS_RDR ? " RDR" : "", status & CIR_IRSTS_RTR ? " RTR" : "", @@ -779,7 +778,7 @@ static irqreturn_t nvt_cir_isr(int irq, void *data) if (!status) { nvt_dbg_verbose("%s exiting, IRSTS 0x0", __func__); nvt_cir_reg_write(nvt, 0xff, CIR_IRSTS); - return IRQ_RETVAL(IRQ_NONE); + return IRQ_NONE; } /* ack/clear all irq flags we've got */ @@ -790,11 +789,10 @@ static irqreturn_t nvt_cir_isr(int irq, void *data) iren = nvt_cir_reg_read(nvt, CIR_IREN); if (!iren) { nvt_dbg_verbose("%s exiting, CIR not enabled", __func__); - return IRQ_RETVAL(IRQ_NONE); + return IRQ_NONE; } - if (debug) - nvt_cir_log_irqs(status, iren); + nvt_cir_log_irqs(status, iren); if (status & CIR_IRSTS_RTR) { /* FIXME: add code for study/learn mode */ @@ -853,7 +851,7 @@ static irqreturn_t nvt_cir_isr(int irq, void *data) } nvt_dbg_verbose("%s done", __func__); - return IRQ_RETVAL(IRQ_HANDLED); + return IRQ_HANDLED; } /* Interrupt service routine for CIR Wake */ @@ -867,7 +865,7 @@ static irqreturn_t nvt_cir_wake_isr(int irq, void *data) status = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRSTS); if (!status) - return IRQ_RETVAL(IRQ_NONE); + return IRQ_NONE; if (status & CIR_WAKE_IRSTS_IR_PENDING) nvt_clear_cir_wake_fifo(nvt); @@ -879,7 +877,7 @@ static irqreturn_t nvt_cir_wake_isr(int irq, void *data) iren = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IREN); if (!iren) { nvt_dbg_wake("%s exiting, wake not enabled", __func__); - return IRQ_RETVAL(IRQ_HANDLED); + return IRQ_HANDLED; } if ((status & CIR_WAKE_IRSTS_PE) && @@ -896,7 +894,7 @@ static irqreturn_t nvt_cir_wake_isr(int irq, void *data) } nvt_dbg_wake("%s done", __func__); - return IRQ_RETVAL(IRQ_HANDLED); + return IRQ_HANDLED; } static void nvt_enable_cir(struct nvt_dev *nvt) @@ -974,7 +972,7 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) struct rc_dev *rdev; int ret = -ENOMEM; - nvt = kzalloc(sizeof(struct nvt_dev), GFP_KERNEL); + nvt = devm_kzalloc(&pdev->dev, sizeof(struct nvt_dev), GFP_KERNEL); if (!nvt) return ret; @@ -1026,9 +1024,7 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) init_waitqueue_head(&nvt->tx.queue); - ret = nvt_hw_detect(nvt); - if (ret) - goto exit_free_dev_rdev; + nvt_hw_detect(nvt); /* Initialize CIR & CIR Wake Logical Devices */ nvt_efm_enable(nvt); @@ -1074,25 +1070,26 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) ret = -EBUSY; /* now claim resources */ - if (!request_region(nvt->cir_addr, + if (!devm_request_region(&pdev->dev, nvt->cir_addr, CIR_IOREG_LENGTH, NVT_DRIVER_NAME)) goto exit_unregister_device; - if (request_irq(nvt->cir_irq, nvt_cir_isr, IRQF_SHARED, - NVT_DRIVER_NAME, (void *)nvt)) - goto exit_release_cir_addr; + if (devm_request_irq(&pdev->dev, nvt->cir_irq, nvt_cir_isr, + IRQF_SHARED, NVT_DRIVER_NAME, (void *)nvt)) + goto exit_unregister_device; - if (!request_region(nvt->cir_wake_addr, + if (!devm_request_region(&pdev->dev, nvt->cir_wake_addr, CIR_IOREG_LENGTH, NVT_DRIVER_NAME)) - goto exit_free_irq; + goto exit_unregister_device; - if (request_irq(nvt->cir_wake_irq, nvt_cir_wake_isr, IRQF_SHARED, - NVT_DRIVER_NAME, (void *)nvt)) - goto exit_release_cir_wake_addr; + if (devm_request_irq(&pdev->dev, nvt->cir_wake_irq, + nvt_cir_wake_isr, IRQF_SHARED, + NVT_DRIVER_NAME, (void *)nvt)) + goto exit_unregister_device; device_init_wakeup(&pdev->dev, true); - nvt_pr(KERN_NOTICE, "driver has been successfully loaded\n"); + dev_notice(&pdev->dev, "driver has been successfully loaded\n"); if (debug) { cir_dump_regs(nvt); cir_wake_dump_regs(nvt); @@ -1100,18 +1097,11 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) return 0; -exit_release_cir_wake_addr: - release_region(nvt->cir_wake_addr, CIR_IOREG_LENGTH); -exit_free_irq: - free_irq(nvt->cir_irq, nvt); -exit_release_cir_addr: - release_region(nvt->cir_addr, CIR_IOREG_LENGTH); exit_unregister_device: rc_unregister_device(rdev); rdev = NULL; exit_free_dev_rdev: rc_free_device(rdev); - kfree(nvt); return ret; } @@ -1129,15 +1119,7 @@ static void nvt_remove(struct pnp_dev *pdev) nvt_enable_wake(nvt); spin_unlock_irqrestore(&nvt->nvt_lock, flags); - /* free resources */ - free_irq(nvt->cir_irq, nvt); - free_irq(nvt->cir_wake_irq, nvt); - release_region(nvt->cir_addr, CIR_IOREG_LENGTH); - release_region(nvt->cir_wake_addr, CIR_IOREG_LENGTH); - rc_unregister_device(nvt->rdev); - - kfree(nvt); } static int nvt_suspend(struct pnp_dev *pdev, pm_message_t state) diff --git a/drivers/media/rc/nuvoton-cir.h b/drivers/media/rc/nuvoton-cir.h index e1cf23c38..0ad15d34e 100644 --- a/drivers/media/rc/nuvoton-cir.h +++ b/drivers/media/rc/nuvoton-cir.h @@ -35,9 +35,6 @@ static int debug; -#define nvt_pr(level, text, ...) \ - printk(level KBUILD_MODNAME ": " text, ## __VA_ARGS__) - #define nvt_dbg(text, ...) \ if (debug) \ printk(KERN_DEBUG \ @@ -64,6 +61,21 @@ static int debug; #define TX_BUF_LEN 256 #define RX_BUF_LEN 32 +#define SIO_ID_MASK 0xfff0 + +enum nvt_chip_ver { + NVT_UNKNOWN = 0, + NVT_W83667HG = 0xa510, + NVT_6775F = 0xb470, + NVT_6776F = 0xc330, + NVT_6779D = 0xc560 +}; + +struct nvt_chip { + const char *name; + enum nvt_chip_ver chip_ver; +}; + struct nvt_dev { struct pnp_dev *pdev; struct rc_dev *rdev; @@ -93,6 +105,7 @@ struct nvt_dev { int cir_irq; int cir_wake_irq; + enum nvt_chip_ver chip_ver; /* hardware id */ u8 chip_major; u8 chip_minor; @@ -326,15 +339,6 @@ struct nvt_dev { #define EFER_EFM_ENABLE 0x87 #define EFER_EFM_DISABLE 0xaa -/* Chip IDs found in CR_CHIP_ID_{HI,LO} */ -#define CHIP_ID_HIGH_667 0xa5 -#define CHIP_ID_HIGH_677B 0xb4 -#define CHIP_ID_HIGH_677C 0xc3 -#define CHIP_ID_LOW_667 0x13 -#define CHIP_ID_LOW_677B2 0x72 -#define CHIP_ID_LOW_677B3 0x73 -#define CHIP_ID_LOW_677C 0x33 - /* Config regs we need to care about */ #define CR_SOFTWARE_RESET 0x02 #define CR_LOGICAL_DEV_SEL 0x07 diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h index b68d4f762..7359f3d03 100644 --- a/drivers/media/rc/rc-core-priv.h +++ b/drivers/media/rc/rc-core-priv.h @@ -167,75 +167,4 @@ void ir_raw_init(void); * loads the compiled decoders for their usage with IR raw events */ -/* from ir-nec-decoder.c */ -#ifdef CONFIG_IR_NEC_DECODER_MODULE -#define load_nec_decode() request_module_nowait("ir-nec-decoder") -#else -static inline void load_nec_decode(void) { } -#endif - -/* from ir-rc5-decoder.c */ -#ifdef CONFIG_IR_RC5_DECODER_MODULE -#define load_rc5_decode() request_module_nowait("ir-rc5-decoder") -#else -static inline void load_rc5_decode(void) { } -#endif - -/* from ir-rc6-decoder.c */ -#ifdef CONFIG_IR_RC6_DECODER_MODULE -#define load_rc6_decode() request_module_nowait("ir-rc6-decoder") -#else -static inline void load_rc6_decode(void) { } -#endif - -/* from ir-jvc-decoder.c */ -#ifdef CONFIG_IR_JVC_DECODER_MODULE -#define load_jvc_decode() request_module_nowait("ir-jvc-decoder") -#else -static inline void load_jvc_decode(void) { } -#endif - -/* from ir-sony-decoder.c */ -#ifdef CONFIG_IR_SONY_DECODER_MODULE -#define load_sony_decode() request_module_nowait("ir-sony-decoder") -#else -static inline void load_sony_decode(void) { } -#endif - -/* from ir-sanyo-decoder.c */ -#ifdef CONFIG_IR_SANYO_DECODER_MODULE -#define load_sanyo_decode() request_module_nowait("ir-sanyo-decoder") -#else -static inline void load_sanyo_decode(void) { } -#endif - -/* from ir-sharp-decoder.c */ -#ifdef CONFIG_IR_SHARP_DECODER_MODULE -#define load_sharp_decode() request_module_nowait("ir-sharp-decoder") -#else -static inline void load_sharp_decode(void) { } -#endif - -/* from ir-mce_kbd-decoder.c */ -#ifdef CONFIG_IR_MCE_KBD_DECODER_MODULE -#define load_mce_kbd_decode() request_module_nowait("ir-mce_kbd-decoder") -#else -static inline void load_mce_kbd_decode(void) { } -#endif - -/* from ir-lirc-codec.c */ -#ifdef CONFIG_IR_LIRC_CODEC_MODULE -#define load_lirc_codec() request_module_nowait("ir-lirc-codec") -#else -static inline void load_lirc_codec(void) { } -#endif - -/* from ir-xmp-decoder.c */ -#ifdef CONFIG_IR_XMP_DECODER_MODULE -#define load_xmp_decode() request_module_nowait("ir-xmp-decoder") -#else -static inline void load_xmp_decode(void) { } -#endif - - #endif /* _RC_CORE_PRIV */ diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c index ad260520a..c69807fe2 100644 --- a/drivers/media/rc/rc-ir-raw.c +++ b/drivers/media/rc/rc-ir-raw.c @@ -59,7 +59,9 @@ static int ir_raw_event_thread(void *data) mutex_lock(&ir_raw_handler_lock); list_for_each_entry(handler, &ir_raw_handler_list, list) - handler->decode(raw->dev, ev); + if (raw->dev->enabled_protocols & handler->protocols || + !handler->protocols) + handler->decode(raw->dev, ev); raw->prev_ev = ev; mutex_unlock(&ir_raw_handler_lock); } @@ -246,6 +248,14 @@ static int change_protocol(struct rc_dev *dev, u64 *rc_type) return 0; } +static void ir_raw_disable_protocols(struct rc_dev *dev, u64 protocols) +{ + mutex_lock(&dev->lock); + dev->enabled_protocols &= ~protocols; + dev->enabled_wakeup_protocols &= ~protocols; + mutex_unlock(&dev->lock); +} + /* * Used to (un)register raw event clients */ @@ -337,33 +347,16 @@ EXPORT_SYMBOL(ir_raw_handler_register); void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler) { struct ir_raw_event_ctrl *raw; + u64 protocols = ir_raw_handler->protocols; mutex_lock(&ir_raw_handler_lock); list_del(&ir_raw_handler->list); - if (ir_raw_handler->raw_unregister) - list_for_each_entry(raw, &ir_raw_client_list, list) + list_for_each_entry(raw, &ir_raw_client_list, list) { + ir_raw_disable_protocols(raw->dev, protocols); + if (ir_raw_handler->raw_unregister) ir_raw_handler->raw_unregister(raw->dev); - available_protocols &= ~ir_raw_handler->protocols; + } + available_protocols &= ~protocols; mutex_unlock(&ir_raw_handler_lock); } EXPORT_SYMBOL(ir_raw_handler_unregister); - -void ir_raw_init(void) -{ - /* Load the decoder modules */ - - load_nec_decode(); - load_rc5_decode(); - load_rc6_decode(); - load_jvc_decode(); - load_sony_decode(); - load_sanyo_decode(); - load_sharp_decode(); - load_mce_kbd_decode(); - load_lirc_codec(); - load_xmp_decode(); - - /* If needed, we may later add some init code. In this case, - it is needed to change the CONFIG_MODULE test at rc-core.h - */ -} diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 3f0f71ada..1042fa331 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -61,7 +61,7 @@ struct rc_map *rc_map_get(const char *name) struct rc_map_list *map; map = seek_rc_map(name); -#ifdef MODULE +#ifdef CONFIG_MODULES if (!map) { int rc = request_module("%s", name); if (rc < 0) { @@ -777,30 +777,31 @@ static struct class rc_class = { * used by the sysfs protocols file. Note that the order * of the entries is relevant. */ -static struct { +static const struct { u64 type; - char *name; + const char *name; + const char *module_name; } proto_names[] = { - { RC_BIT_NONE, "none" }, - { RC_BIT_OTHER, "other" }, - { RC_BIT_UNKNOWN, "unknown" }, + { RC_BIT_NONE, "none", NULL }, + { RC_BIT_OTHER, "other", NULL }, + { RC_BIT_UNKNOWN, "unknown", NULL }, { RC_BIT_RC5 | - RC_BIT_RC5X, "rc-5" }, - { RC_BIT_NEC, "nec" }, + RC_BIT_RC5X, "rc-5", "ir-rc5-decoder" }, + { RC_BIT_NEC, "nec", "ir-nec-decoder" }, { RC_BIT_RC6_0 | RC_BIT_RC6_6A_20 | RC_BIT_RC6_6A_24 | RC_BIT_RC6_6A_32 | - RC_BIT_RC6_MCE, "rc-6" }, - { RC_BIT_JVC, "jvc" }, + RC_BIT_RC6_MCE, "rc-6", "ir-rc6-decoder" }, + { RC_BIT_JVC, "jvc", "ir-jvc-decoder" }, { RC_BIT_SONY12 | RC_BIT_SONY15 | - RC_BIT_SONY20, "sony" }, - { RC_BIT_RC5_SZ, "rc-5-sz" }, - { RC_BIT_SANYO, "sanyo" }, - { RC_BIT_SHARP, "sharp" }, - { RC_BIT_MCE_KBD, "mce_kbd" }, - { RC_BIT_XMP, "xmp" }, + RC_BIT_SONY20, "sony", "ir-sony-decoder" }, + { RC_BIT_RC5_SZ, "rc-5-sz", "ir-rc5-decoder" }, + { RC_BIT_SANYO, "sanyo", "ir-sanyo-decoder" }, + { RC_BIT_SHARP, "sharp", "ir-sharp-decoder" }, + { RC_BIT_MCE_KBD, "mce_kbd", "ir-mce_kbd-decoder" }, + { RC_BIT_XMP, "xmp", "ir-xmp-decoder" }, }; /** @@ -979,6 +980,48 @@ static int parse_protocol_change(u64 *protocols, const char *buf) return count; } +static void ir_raw_load_modules(u64 *protocols) + +{ + u64 available; + int i, ret; + + for (i = 0; i < ARRAY_SIZE(proto_names); i++) { + if (proto_names[i].type == RC_BIT_NONE || + proto_names[i].type & (RC_BIT_OTHER | RC_BIT_UNKNOWN)) + continue; + + available = ir_raw_get_allowed_protocols(); + if (!(*protocols & proto_names[i].type & ~available)) + continue; + + if (!proto_names[i].module_name) { + pr_err("Can't enable IR protocol %s\n", + proto_names[i].name); + *protocols &= ~proto_names[i].type; + continue; + } + + ret = request_module("%s", proto_names[i].module_name); + if (ret < 0) { + pr_err("Couldn't load IR protocol module %s\n", + proto_names[i].module_name); + *protocols &= ~proto_names[i].type; + continue; + } + msleep(20); + available = ir_raw_get_allowed_protocols(); + if (!(*protocols & proto_names[i].type & ~available)) + continue; + + pr_err("Loaded IR protocol module %s, \ + but protocol %s still not available\n", + proto_names[i].module_name, + proto_names[i].name); + *protocols &= ~proto_names[i].type; + } +} + /** * store_protocols() - changes the current/wakeup IR protocol(s) * @device: the device descriptor @@ -1045,6 +1088,9 @@ static ssize_t store_protocols(struct device *device, goto out; } + if (dev->driver_type == RC_DRIVER_IR_RAW) + ir_raw_load_modules(&new_protocols); + if (new_protocols != old_protocols) { *current_protocols = new_protocols; IR_dprintk(1, "Protocols changed to 0x%llx\n", @@ -1420,17 +1466,13 @@ int rc_register_device(struct rc_dev *dev) dev->input_dev->rep[REP_PERIOD] = 125; path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL); - printk(KERN_INFO "%s: %s as %s\n", - dev_name(&dev->dev), - dev->input_name ? dev->input_name : "Unspecified device", - path ? path : "N/A"); + dev_info(&dev->dev, "%s as %s\n", + dev->input_name ?: "Unspecified device", path ?: "N/A"); kfree(path); if (dev->driver_type == RC_DRIVER_IR_RAW) { - /* Load raw decoders, if they aren't already */ if (!raw_init) { - IR_dprintk(1, "Loading raw decoders\n"); - ir_raw_init(); + request_module_nowait("ir-lirc-codec"); raw_init = true; } /* calls ir_register_device so unlock mutex here*/ diff --git a/drivers/media/rc/st_rc.c b/drivers/media/rc/st_rc.c index 37d040158..1fa0c9d1c 100644 --- a/drivers/media/rc/st_rc.c +++ b/drivers/media/rc/st_rc.c @@ -16,6 +16,7 @@ #include <linux/reset.h> #include <media/rc-core.h> #include <linux/pinctrl/consumer.h> +#include <linux/pm_wakeirq.h> struct st_rc_device { struct device *dev; @@ -190,6 +191,9 @@ static void st_rc_hardware_init(struct st_rc_device *dev) static int st_rc_remove(struct platform_device *pdev) { struct st_rc_device *rc_dev = platform_get_drvdata(pdev); + + dev_pm_clear_wake_irq(&pdev->dev); + device_init_wakeup(&pdev->dev, false); clk_disable_unprepare(rc_dev->sys_clock); rc_unregister_device(rc_dev->rdev); return 0; @@ -298,22 +302,22 @@ static int st_rc_probe(struct platform_device *pdev) rdev->map_name = RC_MAP_LIRC; rdev->input_name = "ST Remote Control Receiver"; - /* enable wake via this device */ - device_set_wakeup_capable(dev, true); - device_set_wakeup_enable(dev, true); - ret = rc_register_device(rdev); if (ret < 0) goto clkerr; rc_dev->rdev = rdev; if (devm_request_irq(dev, rc_dev->irq, st_rc_rx_interrupt, - IRQF_NO_SUSPEND, IR_ST_NAME, rc_dev) < 0) { + 0, IR_ST_NAME, rc_dev) < 0) { dev_err(dev, "IRQ %d register failed\n", rc_dev->irq); ret = -EINVAL; goto rcerr; } + /* enable wake via this device */ + device_init_wakeup(dev, true); + dev_pm_set_wake_irq(dev, rc_dev->irq); + /** * for LIRC_MODE_MODE2 or LIRC_MODE_PULSE or LIRC_MODE_RAW * lircd expects a long space first before a signal train to sync. diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c index 5a17cb88f..815243c65 100644 --- a/drivers/media/rc/streamzap.c +++ b/drivers/media/rc/streamzap.c @@ -34,6 +34,7 @@ #include <linux/device.h> #include <linux/module.h> #include <linux/slab.h> +#include <linux/ktime.h> #include <linux/usb.h> #include <linux/usb/input.h> #include <media/rc-core.h> @@ -96,8 +97,8 @@ struct streamzap_ir { /* sum of signal lengths received since signal start */ unsigned long sum; /* start time of signal; necessary for gap tracking */ - struct timeval signal_last; - struct timeval signal_start; + ktime_t signal_last; + ktime_t signal_start; bool timeout_enabled; char name[128]; @@ -136,20 +137,18 @@ static void sz_push_full_pulse(struct streamzap_ir *sz, DEFINE_IR_RAW_EVENT(rawir); if (sz->idle) { - long deltv; + int delta; sz->signal_last = sz->signal_start; - do_gettimeofday(&sz->signal_start); + sz->signal_start = ktime_get_real(); - deltv = sz->signal_start.tv_sec - sz->signal_last.tv_sec; + delta = ktime_us_delta(sz->signal_start, sz->signal_last); rawir.pulse = false; - if (deltv > 15) { + if (delta > (15 * USEC_PER_SEC)) { /* really long time */ rawir.duration = IR_MAX_DURATION; } else { - rawir.duration = (int)(deltv * 1000000 + - sz->signal_start.tv_usec - - sz->signal_last.tv_usec); + rawir.duration = delta; rawir.duration -= sz->sum; rawir.duration = US_TO_NS(rawir.duration); rawir.duration = (rawir.duration > IR_MAX_DURATION) ? @@ -428,7 +427,7 @@ static int streamzap_probe(struct usb_interface *intf, sz->max_timeout = US_TO_NS(SZ_TIMEOUT * SZ_RESOLUTION); #endif - do_gettimeofday(&sz->signal_start); + sz->signal_start = ktime_get_real(); /* Complete final initialisations */ usb_fill_int_urb(sz->urb_in, usbdev, pipe, sz->buf_in, diff --git a/drivers/media/tuners/max2165.c b/drivers/media/tuners/max2165.c index 95ed46f2c..353b178be 100644 --- a/drivers/media/tuners/max2165.c +++ b/drivers/media/tuners/max2165.c @@ -385,7 +385,7 @@ static const struct dvb_tuner_ops max2165_tuner_ops = { .info = { .name = "Maxim MAX2165", .frequency_min = 470000000, - .frequency_max = 780000000, + .frequency_max = 862000000, .frequency_step = 50000, }, diff --git a/drivers/media/tuners/mt2063.c b/drivers/media/tuners/mt2063.c index 9e9c5eb4c..6457ac91e 100644 --- a/drivers/media/tuners/mt2063.c +++ b/drivers/media/tuners/mt2063.c @@ -225,7 +225,6 @@ struct mt2063_state { const struct mt2063_config *config; struct dvb_tuner_ops ops; struct dvb_frontend *frontend; - struct tuner_state status; u32 frequency; u32 srate; diff --git a/drivers/media/usb/airspy/airspy.c b/drivers/media/usb/airspy/airspy.c index 565a59310..0d4ac5947 100644 --- a/drivers/media/usb/airspy/airspy.c +++ b/drivers/media/usb/airspy/airspy.c @@ -316,7 +316,7 @@ static void airspy_urb_complete(struct urb *urb) len = airspy_convert_stream(s, ptr, urb->transfer_buffer, urb->actual_length); vb2_set_plane_payload(&fbuf->vb.vb2_buf, 0, len); - v4l2_get_timestamp(&fbuf->vb.timestamp); + fbuf->vb.vb2_buf.timestamp = ktime_get_ns(); fbuf->vb.sequence = s->sequence++; vb2_buffer_done(&fbuf->vb.vb2_buf, VB2_BUF_STATE_DONE); } @@ -488,7 +488,7 @@ static void airspy_disconnect(struct usb_interface *intf) /* Videobuf2 operations */ static int airspy_queue_setup(struct vb2_queue *vq, - const void *parg, unsigned int *nbuffers, + unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) { struct airspy *s = vb2_get_drv_priv(vq); diff --git a/drivers/media/usb/as102/as102_fw.c b/drivers/media/usb/as102/as102_fw.c index dd3127df6..82a5c7767 100644 --- a/drivers/media/usb/as102/as102_fw.c +++ b/drivers/media/usb/as102/as102_fw.c @@ -198,6 +198,7 @@ int as102_fw_upload(struct as10x_bus_adapter_t *bus_adap) pr_info("%s: firmware: %s loaded with success\n", DRIVER_NAME, fw1); release_firmware(firmware); + firmware = NULL; /* wait for boot to complete */ mdelay(100); diff --git a/drivers/media/usb/au0828/au0828-cards.c b/drivers/media/usb/au0828/au0828-cards.c index 6b469e8c4..ca861aea6 100644 --- a/drivers/media/usb/au0828/au0828-cards.c +++ b/drivers/media/usb/au0828/au0828-cards.c @@ -228,6 +228,10 @@ void au0828_card_analog_fe_setup(struct au0828_dev *dev) "au8522", 0x8e >> 1, NULL); if (sd == NULL) pr_err("analog subdev registration failed\n"); +#ifdef CONFIG_MEDIA_CONTROLLER + if (sd) + dev->decoder = &sd->entity; +#endif } /* Setup tuners */ diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c index 0934024fb..9e29e70a7 100644 --- a/drivers/media/usb/au0828/au0828-core.c +++ b/drivers/media/usb/au0828/au0828-core.c @@ -27,6 +27,9 @@ #include <media/v4l2-common.h> #include <linux/mutex.h> +/* Due to enum tuner_pad_index */ +#include <media/tuner.h> + /* * 1 = General debug messages * 2 = USB handling @@ -127,8 +130,23 @@ static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value, return status; } +static void au0828_unregister_media_device(struct au0828_dev *dev) +{ + +#ifdef CONFIG_MEDIA_CONTROLLER + if (dev->media_dev) { + media_device_unregister(dev->media_dev); + media_device_cleanup(dev->media_dev); + kfree(dev->media_dev); + dev->media_dev = NULL; + } +#endif +} + static void au0828_usb_release(struct au0828_dev *dev) { + au0828_unregister_media_device(dev); + /* I2C */ au0828_i2c_unregister(dev); @@ -136,6 +154,20 @@ static void au0828_usb_release(struct au0828_dev *dev) } #ifdef CONFIG_VIDEO_AU0828_V4L2 + +static void au0828_usb_v4l2_media_release(struct au0828_dev *dev) +{ +#ifdef CONFIG_MEDIA_CONTROLLER + int i; + + for (i = 0; i < AU0828_MAX_INPUT; i++) { + if (AUVI_INPUT(i).type == AU0828_VMUX_UNDEFINED) + return; + media_device_unregister_entity(&dev->input_ent[i]); + } +#endif +} + static void au0828_usb_v4l2_release(struct v4l2_device *v4l2_dev) { struct au0828_dev *dev = @@ -143,6 +175,7 @@ static void au0828_usb_v4l2_release(struct v4l2_device *v4l2_dev) v4l2_ctrl_handler_free(&dev->v4l2_ctrl_hdl); v4l2_device_unregister(&dev->v4l2_dev); + au0828_usb_v4l2_media_release(dev); au0828_usb_release(dev); } #endif @@ -174,12 +207,123 @@ static void au0828_usb_disconnect(struct usb_interface *interface) au0828_analog_unregister(dev); v4l2_device_disconnect(&dev->v4l2_dev); v4l2_device_put(&dev->v4l2_dev); + /* + * No need to call au0828_usb_release() if V4L2 is enabled, + * as this is already called via au0828_usb_v4l2_release() + */ return; } #endif au0828_usb_release(dev); } +static int au0828_media_device_init(struct au0828_dev *dev, + struct usb_device *udev) +{ +#ifdef CONFIG_MEDIA_CONTROLLER + struct media_device *mdev; + + mdev = kzalloc(sizeof(*mdev), GFP_KERNEL); + if (!mdev) + return -ENOMEM; + + mdev->dev = &udev->dev; + + if (!dev->board.name) + strlcpy(mdev->model, "unknown au0828", sizeof(mdev->model)); + else + strlcpy(mdev->model, dev->board.name, sizeof(mdev->model)); + if (udev->serial) + strlcpy(mdev->serial, udev->serial, sizeof(mdev->serial)); + strcpy(mdev->bus_info, udev->devpath); + mdev->hw_revision = le16_to_cpu(udev->descriptor.bcdDevice); + mdev->driver_version = LINUX_VERSION_CODE; + + media_device_init(mdev); + + dev->media_dev = mdev; +#endif + return 0; +} + + +static int au0828_create_media_graph(struct au0828_dev *dev) +{ +#ifdef CONFIG_MEDIA_CONTROLLER + struct media_device *mdev = dev->media_dev; + struct media_entity *entity; + struct media_entity *tuner = NULL, *decoder = NULL; + int i, ret; + + if (!mdev) + return 0; + + media_device_for_each_entity(entity, mdev) { + switch (entity->function) { + case MEDIA_ENT_F_TUNER: + tuner = entity; + break; + case MEDIA_ENT_F_ATV_DECODER: + decoder = entity; + break; + } + } + + /* Analog setup, using tuner as a link */ + + /* Something bad happened! */ + if (!decoder) + return -EINVAL; + + if (tuner) { + ret = media_create_pad_link(tuner, TUNER_PAD_IF_OUTPUT, + decoder, 0, + MEDIA_LNK_FL_ENABLED); + if (ret) + return ret; + } + ret = media_create_pad_link(decoder, 1, &dev->vdev.entity, 0, + MEDIA_LNK_FL_ENABLED); + if (ret) + return ret; + ret = media_create_pad_link(decoder, 2, &dev->vbi_dev.entity, 0, + MEDIA_LNK_FL_ENABLED); + if (ret) + return ret; + + for (i = 0; i < AU0828_MAX_INPUT; i++) { + struct media_entity *ent = &dev->input_ent[i]; + + if (AUVI_INPUT(i).type == AU0828_VMUX_UNDEFINED) + break; + + switch (AUVI_INPUT(i).type) { + case AU0828_VMUX_CABLE: + case AU0828_VMUX_TELEVISION: + case AU0828_VMUX_DVB: + if (!tuner) + break; + + ret = media_create_pad_link(ent, 0, tuner, + TUNER_PAD_RF_INPUT, + MEDIA_LNK_FL_ENABLED); + if (ret) + return ret; + break; + case AU0828_VMUX_COMPOSITE: + case AU0828_VMUX_SVIDEO: + default: /* AU0828_VMUX_DEBUG */ + /* FIXME: fix the decoder PAD */ + ret = media_create_pad_link(ent, 0, decoder, 0, 0); + if (ret) + return ret; + break; + } + } +#endif + return 0; +} + static int au0828_usb_probe(struct usb_interface *interface, const struct usb_device_id *id) { @@ -224,11 +368,23 @@ static int au0828_usb_probe(struct usb_interface *interface, dev->boardnr = id->driver_info; dev->board = au0828_boards[dev->boardnr]; + /* Initialize the media controller */ + retval = au0828_media_device_init(dev, usbdev); + if (retval) { + pr_err("%s() au0828_media_device_init failed\n", + __func__); + mutex_unlock(&dev->lock); + kfree(dev); + return retval; + } #ifdef CONFIG_VIDEO_AU0828_V4L2 dev->v4l2_dev.release = au0828_usb_v4l2_release; /* Create the v4l2_device */ +#ifdef CONFIG_MEDIA_CONTROLLER + dev->v4l2_dev.mdev = dev->media_dev; +#endif retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev); if (retval) { pr_err("%s() v4l2_device_register failed\n", @@ -287,6 +443,21 @@ static int au0828_usb_probe(struct usb_interface *interface, mutex_unlock(&dev->lock); + retval = au0828_create_media_graph(dev); + if (retval) { + pr_err("%s() au0282_dev_register failed to create graph\n", + __func__); + goto done; + } + +#ifdef CONFIG_MEDIA_CONTROLLER + retval = media_device_register(dev->media_dev); +#endif + +done: + if (retval < 0) + au0828_usb_disconnect(interface); + return retval; } diff --git a/drivers/media/usb/au0828/au0828-dvb.c b/drivers/media/usb/au0828/au0828-dvb.c index c267d76f5..94363a3ba 100644 --- a/drivers/media/usb/au0828/au0828-dvb.c +++ b/drivers/media/usb/au0828/au0828-dvb.c @@ -415,6 +415,11 @@ static int dvb_register(struct au0828_dev *dev) result); goto fail_adapter; } + +#ifdef CONFIG_MEDIA_CONTROLLER_DVB + dvb->adapter.mdev = dev->media_dev; +#endif + dvb->adapter.priv = dev; /* register frontend */ @@ -480,8 +485,15 @@ static int dvb_register(struct au0828_dev *dev) dvb->start_count = 0; dvb->stop_count = 0; + + result = dvb_create_media_graph(&dvb->adapter, false); + if (result < 0) + goto fail_create_graph; + return 0; +fail_create_graph: + dvb_net_release(&dvb->net); fail_fe_conn: dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); fail_fe_mem: diff --git a/drivers/media/usb/au0828/au0828-vbi.c b/drivers/media/usb/au0828/au0828-vbi.c index 130c8b49b..b4efc103a 100644 --- a/drivers/media/usb/au0828/au0828-vbi.c +++ b/drivers/media/usb/au0828/au0828-vbi.c @@ -30,23 +30,17 @@ /* ------------------------------------------------------------------ */ -static int vbi_queue_setup(struct vb2_queue *vq, const void *parg, +static int vbi_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) { - const struct v4l2_format *fmt = parg; struct au0828_dev *dev = vb2_get_drv_priv(vq); - unsigned long img_size = dev->vbi_width * dev->vbi_height * 2; - unsigned long size; - - size = fmt ? (fmt->fmt.vbi.samples_per_line * - (fmt->fmt.vbi.count[0] + fmt->fmt.vbi.count[1])) : img_size; - if (size < img_size) - return -EINVAL; + unsigned long size = dev->vbi_width * dev->vbi_height * 2; + if (*nplanes) + return sizes[0] < size ? -EINVAL : 0; *nplanes = 1; sizes[0] = size; - return 0; } diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 45c622e23..a13625722 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -314,7 +314,7 @@ static inline void buffer_filled(struct au0828_dev *dev, vb->sequence = dev->vbi_frame_count++; vb->field = V4L2_FIELD_INTERLACED; - v4l2_get_timestamp(&vb->timestamp); + vb->vb2_buf.timestamp = ktime_get_ns(); vb2_buffer_done(&vb->vb2_buf, VB2_BUF_STATE_DONE); } @@ -638,22 +638,78 @@ static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb) return rc; } -static int queue_setup(struct vb2_queue *vq, const void *parg, +static int au0828_enable_analog_tuner(struct au0828_dev *dev) +{ +#ifdef CONFIG_MEDIA_CONTROLLER + struct media_device *mdev = dev->media_dev; + struct media_entity *source; + struct media_link *link, *found_link = NULL; + int ret, active_links = 0; + + if (!mdev || !dev->decoder) + return 0; + + /* + * This will find the tuner that is connected into the decoder. + * Technically, this is not 100% correct, as the device may be + * using an analog input instead of the tuner. However, as we can't + * do DVB streaming while the DMA engine is being used for V4L2, + * this should be enough for the actual needs. + */ + list_for_each_entry(link, &dev->decoder->links, list) { + if (link->sink->entity == dev->decoder) { + found_link = link; + if (link->flags & MEDIA_LNK_FL_ENABLED) + active_links++; + break; + } + } + + if (active_links == 1 || !found_link) + return 0; + + source = found_link->source->entity; + list_for_each_entry(link, &source->links, list) { + struct media_entity *sink; + int flags = 0; + + sink = link->sink->entity; + + if (sink == dev->decoder) + flags = MEDIA_LNK_FL_ENABLED; + + ret = media_entity_setup_link(link, flags); + if (ret) { + pr_err( + "Couldn't change link %s->%s to %s. Error %d\n", + source->name, sink->name, + flags ? "enabled" : "disabled", + ret); + return ret; + } else + au0828_isocdbg( + "link %s->%s was %s\n", + source->name, sink->name, + flags ? "ENABLED" : "disabled"); + } +#endif + return 0; +} + +static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) { - const struct v4l2_format *fmt = parg; struct au0828_dev *dev = vb2_get_drv_priv(vq); - unsigned long img_size = dev->height * dev->bytesperline; - unsigned long size; - - size = fmt ? fmt->fmt.pix.sizeimage : img_size; - if (size < img_size) - return -EINVAL; + unsigned long size = dev->height * dev->bytesperline; + if (*nplanes) + return sizes[0] < size ? -EINVAL : 0; *nplanes = 1; sizes[0] = size; + au0828_enable_analog_tuner(dev); + return 0; } @@ -1739,6 +1795,68 @@ static int au0828_vb2_setup(struct au0828_dev *dev) return 0; } +static void au0828_analog_create_entities(struct au0828_dev *dev) +{ +#if defined(CONFIG_MEDIA_CONTROLLER) + static const char * const inames[] = { + [AU0828_VMUX_COMPOSITE] = "Composite", + [AU0828_VMUX_SVIDEO] = "S-Video", + [AU0828_VMUX_CABLE] = "Cable TV", + [AU0828_VMUX_TELEVISION] = "Television", + [AU0828_VMUX_DVB] = "DVB", + [AU0828_VMUX_DEBUG] = "tv debug" + }; + int ret, i; + + /* Initialize Video and VBI pads */ + dev->video_pad.flags = MEDIA_PAD_FL_SINK; + ret = media_entity_pads_init(&dev->vdev.entity, 1, &dev->video_pad); + if (ret < 0) + pr_err("failed to initialize video media entity!\n"); + + dev->vbi_pad.flags = MEDIA_PAD_FL_SINK; + ret = media_entity_pads_init(&dev->vbi_dev.entity, 1, &dev->vbi_pad); + if (ret < 0) + pr_err("failed to initialize vbi media entity!\n"); + + /* Create entities for each input connector */ + for (i = 0; i < AU0828_MAX_INPUT; i++) { + struct media_entity *ent = &dev->input_ent[i]; + + if (AUVI_INPUT(i).type == AU0828_VMUX_UNDEFINED) + break; + + ent->name = inames[AUVI_INPUT(i).type]; + ent->flags = MEDIA_ENT_FL_CONNECTOR; + dev->input_pad[i].flags = MEDIA_PAD_FL_SOURCE; + + switch (AUVI_INPUT(i).type) { + case AU0828_VMUX_COMPOSITE: + ent->function = MEDIA_ENT_F_CONN_COMPOSITE; + break; + case AU0828_VMUX_SVIDEO: + ent->function = MEDIA_ENT_F_CONN_SVIDEO; + break; + case AU0828_VMUX_CABLE: + case AU0828_VMUX_TELEVISION: + case AU0828_VMUX_DVB: + ent->function = MEDIA_ENT_F_CONN_RF; + break; + default: /* AU0828_VMUX_DEBUG */ + continue; + } + + ret = media_entity_pads_init(ent, 1, &dev->input_pad[i]); + if (ret < 0) + pr_err("failed to initialize input pad[%d]!\n", i); + + ret = media_device_register_entity(dev->media_dev, ent); + if (ret < 0) + pr_err("failed to register input entity %d!\n", i); + } +#endif +} + /**************************************************************************/ int au0828_analog_register(struct au0828_dev *dev, @@ -1827,6 +1945,9 @@ int au0828_analog_register(struct au0828_dev *dev, dev->vbi_dev.queue->lock = &dev->vb_vbi_queue_lock; strcpy(dev->vbi_dev.name, "au0828a vbi"); + /* Init entities at the Media Controller */ + au0828_analog_create_entities(dev); + /* initialize videobuf2 stuff */ retval = au0828_vb2_setup(dev); if (retval != 0) { diff --git a/drivers/media/usb/au0828/au0828.h b/drivers/media/usb/au0828/au0828.h index 60b59391e..8276072bc 100644 --- a/drivers/media/usb/au0828/au0828.h +++ b/drivers/media/usb/au0828/au0828.h @@ -33,6 +33,7 @@ #include <media/v4l2-device.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-fh.h> +#include <media/media-device.h> /* DVB */ #include "demux.h" @@ -93,7 +94,6 @@ struct au0828_board { unsigned char has_ir_i2c:1; unsigned char has_analog:1; struct au0828_input input[AU0828_MAX_INPUT]; - }; struct au0828_dvb { @@ -276,6 +276,14 @@ struct au0828_dev { /* Preallocated transfer digital transfer buffers */ char *dig_transfer_buffer[URB_COUNT]; + +#ifdef CONFIG_MEDIA_CONTROLLER + struct media_device *media_dev; + struct media_pad video_pad, vbi_pad; + struct media_entity *decoder; + struct media_entity input_ent[AU0828_MAX_INPUT]; + struct media_pad input_pad[AU0828_MAX_INPUT]; +#endif }; diff --git a/drivers/media/usb/cpia2/cpia2_usb.c b/drivers/media/usb/cpia2/cpia2_usb.c index 351a78a84..c1aa1ab2e 100644 --- a/drivers/media/usb/cpia2/cpia2_usb.c +++ b/drivers/media/usb/cpia2/cpia2_usb.c @@ -890,8 +890,7 @@ static void cpia2_usb_disconnect(struct usb_interface *intf) DBG("Wakeup waiting processes\n"); cam->curbuff->status = FRAME_READY; cam->curbuff->length = 0; - if (waitqueue_active(&cam->wq_stream)) - wake_up_interruptible(&cam->wq_stream); + wake_up_interruptible(&cam->wq_stream); } DBG("Releasing interface\n"); diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c index 04f3e0ae6..de6258ece 100644 --- a/drivers/media/usb/cx231xx/cx231xx-417.c +++ b/drivers/media/usb/cx231xx/cx231xx-417.c @@ -37,7 +37,7 @@ #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> #include <media/v4l2-event.h> -#include <media/cx2341x.h> +#include <media/drv-intf/cx2341x.h> #include <media/tuner.h> #define CX231xx_FIRM_IMAGE_SIZE 376836 @@ -1492,6 +1492,27 @@ static struct videobuf_queue_ops cx231xx_qops = { /* ------------------------------------------------------------------ */ +static int vidioc_cropcap(struct file *file, void *priv, + struct v4l2_cropcap *cc) +{ + struct cx231xx_fh *fh = priv; + struct cx231xx *dev = fh->dev; + bool is_50hz = dev->encodernorm.id & V4L2_STD_625_50; + + if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + cc->bounds.left = 0; + cc->bounds.top = 0; + cc->bounds.width = dev->ts1.width; + cc->bounds.height = dev->ts1.height; + cc->defrect = cc->bounds; + cc->pixelaspect.numerator = is_50hz ? 54 : 11; + cc->pixelaspect.denominator = is_50hz ? 59 : 10; + + return 0; +} + static int vidioc_g_std(struct file *file, void *fh0, v4l2_std_id *norm) { struct cx231xx_fh *fh = file->private_data; @@ -1834,6 +1855,7 @@ static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { .vidioc_g_input = cx231xx_g_input, .vidioc_s_input = cx231xx_s_input, .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_cropcap = vidioc_cropcap, .vidioc_querycap = cx231xx_querycap, .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, @@ -1901,7 +1923,7 @@ static int cx231xx_s_audio_sampling_freq(struct cx2341x_handler *cxhdl, u32 idx) return 0; } -static struct cx2341x_handler_ops cx231xx_ops = { +static const struct cx2341x_handler_ops cx231xx_ops = { /* needed for the video clock freq */ .s_audio_sampling_freq = cx231xx_s_audio_sampling_freq, /* needed for setting up the video resolution */ diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c index ce5e538c4..a3d0d7cef 100644 --- a/drivers/media/usb/cx231xx/cx231xx-cards.c +++ b/drivers/media/usb/cx231xx/cx231xx-cards.c @@ -30,7 +30,7 @@ #include <media/tveeprom.h> #include <media/v4l2-common.h> -#include <media/cx25840.h> +#include <media/drv-intf/cx25840.h> #include "dvb-usb-ids.h" #include "xc5000.h" #include "tda18271.h" @@ -352,7 +352,7 @@ struct cx231xx_board cx231xx_boards[] = { .agc_analog_digital_select_gpio = 0x0c, .gpio_pin_status_mask = 0x4001000, .tuner_i2c_master = I2C_1_MUX_1, - .demod_i2c_master = I2C_2, + .demod_i2c_master = I2C_1_MUX_1, .has_dvb = 1, .demod_addr = 0x0e, .norm = V4L2_STD_NTSC, @@ -713,7 +713,7 @@ struct cx231xx_board cx231xx_boards[] = { .agc_analog_digital_select_gpio = 0x0c, .gpio_pin_status_mask = 0x4001000, .tuner_i2c_master = I2C_1_MUX_3, - .demod_i2c_master = I2C_2, + .demod_i2c_master = I2C_1_MUX_3, .has_dvb = 1, .demod_addr = 0x0e, .norm = V4L2_STD_PAL, @@ -752,7 +752,7 @@ struct cx231xx_board cx231xx_boards[] = { .agc_analog_digital_select_gpio = 0x0c, .gpio_pin_status_mask = 0x4001000, .tuner_i2c_master = I2C_1_MUX_3, - .demod_i2c_master = I2C_2, + .demod_i2c_master = I2C_1_MUX_3, .has_dvb = 1, .demod_addr = 0x0e, .norm = V4L2_STD_PAL, @@ -791,7 +791,7 @@ struct cx231xx_board cx231xx_boards[] = { .agc_analog_digital_select_gpio = 0x0c, .gpio_pin_status_mask = 0x4001000, .tuner_i2c_master = I2C_1_MUX_3, - .demod_i2c_master = I2C_2, + .demod_i2c_master = I2C_1_MUX_3, .has_dvb = 1, .demod_addr = 0x0e, .norm = V4L2_STD_NTSC, @@ -1172,6 +1172,7 @@ static void cx231xx_unregister_media_device(struct cx231xx *dev) #ifdef CONFIG_MEDIA_CONTROLLER if (dev->media_dev) { media_device_unregister(dev->media_dev); + media_device_cleanup(dev->media_dev); kfree(dev->media_dev); dev->media_dev = NULL; } @@ -1185,8 +1186,6 @@ static void cx231xx_unregister_media_device(struct cx231xx *dev) */ void cx231xx_release_resources(struct cx231xx *dev) { - cx231xx_unregister_media_device(dev); - cx231xx_release_analog_resources(dev); cx231xx_remove_from_devlist(dev); @@ -1199,22 +1198,23 @@ void cx231xx_release_resources(struct cx231xx *dev) /* delete v4l2 device */ v4l2_device_unregister(&dev->v4l2_dev); + cx231xx_unregister_media_device(dev); + usb_put_dev(dev->udev); /* Mark device as unused */ clear_bit(dev->devno, &cx231xx_devused); } -static void cx231xx_media_device_register(struct cx231xx *dev, - struct usb_device *udev) +static int cx231xx_media_device_init(struct cx231xx *dev, + struct usb_device *udev) { #ifdef CONFIG_MEDIA_CONTROLLER struct media_device *mdev; - int ret; mdev = kzalloc(sizeof(*mdev), GFP_KERNEL); if (!mdev) - return; + return -ENOMEM; mdev->dev = dev->dev; strlcpy(mdev->model, dev->board.name, sizeof(mdev->model)); @@ -1224,35 +1224,30 @@ static void cx231xx_media_device_register(struct cx231xx *dev, mdev->hw_revision = le16_to_cpu(udev->descriptor.bcdDevice); mdev->driver_version = LINUX_VERSION_CODE; - ret = media_device_register(mdev); - if (ret) { - dev_err(dev->dev, - "Couldn't create a media device. Error: %d\n", - ret); - kfree(mdev); - return; - } + media_device_init(mdev); dev->media_dev = mdev; #endif + return 0; } -static void cx231xx_create_media_graph(struct cx231xx *dev) +static int cx231xx_create_media_graph(struct cx231xx *dev) { #ifdef CONFIG_MEDIA_CONTROLLER struct media_device *mdev = dev->media_dev; struct media_entity *entity; struct media_entity *tuner = NULL, *decoder = NULL; + int ret; if (!mdev) - return; + return 0; media_device_for_each_entity(entity, mdev) { - switch (entity->type) { - case MEDIA_ENT_T_V4L2_SUBDEV_TUNER: + switch (entity->function) { + case MEDIA_ENT_F_TUNER: tuner = entity; break; - case MEDIA_ENT_T_V4L2_SUBDEV_DECODER: + case MEDIA_ENT_F_ATV_DECODER: decoder = entity; break; } @@ -1261,16 +1256,24 @@ static void cx231xx_create_media_graph(struct cx231xx *dev) /* Analog setup, using tuner as a link */ if (!decoder) - return; + return 0; - if (tuner) - media_entity_create_link(tuner, 0, decoder, 0, - MEDIA_LNK_FL_ENABLED); - media_entity_create_link(decoder, 1, &dev->vdev.entity, 0, - MEDIA_LNK_FL_ENABLED); - media_entity_create_link(decoder, 2, &dev->vbi_dev.entity, 0, - MEDIA_LNK_FL_ENABLED); + if (tuner) { + ret = media_create_pad_link(tuner, TUNER_PAD_IF_OUTPUT, decoder, 0, + MEDIA_LNK_FL_ENABLED); + if (ret < 0) + return ret; + } + ret = media_create_pad_link(decoder, 1, &dev->vdev.entity, 0, + MEDIA_LNK_FL_ENABLED); + if (ret < 0) + return ret; + ret = media_create_pad_link(decoder, 2, &dev->vbi_dev.entity, 0, + MEDIA_LNK_FL_ENABLED); + if (ret < 0) + return ret; #endif + return 0; } /* @@ -1660,8 +1663,12 @@ static int cx231xx_usb_probe(struct usb_interface *interface, /* save our data pointer in this interface device */ usb_set_intfdata(interface, dev); - /* Register the media controller */ - cx231xx_media_device_register(dev, udev); + /* Initialize the media controller */ + retval = cx231xx_media_device_init(dev, udev); + if (retval) { + dev_err(d, "cx231xx_media_device_init failed\n"); + goto err_media_init; + } /* Create v4l2 device */ #ifdef CONFIG_MEDIA_CONTROLLER @@ -1732,9 +1739,19 @@ static int cx231xx_usb_probe(struct usb_interface *interface, /* load other modules required */ request_modules(dev); - cx231xx_create_media_graph(dev); + retval = cx231xx_create_media_graph(dev); + if (retval < 0) + goto done; + +#ifdef CONFIG_MEDIA_CONTROLLER + retval = media_device_register(dev->media_dev); +#endif + +done: + if (retval < 0) + cx231xx_release_resources(dev); + return retval; - return 0; err_video_alt: /* cx231xx_uninit_dev: */ cx231xx_close_extension(dev); @@ -1746,6 +1763,8 @@ err_video_alt: err_init: v4l2_device_unregister(&dev->v4l2_dev); err_v4l2: + cx231xx_unregister_media_device(dev); +err_media_init: usb_set_intfdata(interface, NULL); err_if: usb_put_dev(udev); diff --git a/drivers/media/usb/cx231xx/cx231xx-core.c b/drivers/media/usb/cx231xx/cx231xx-core.c index a2fd49b6b..f497888d9 100644 --- a/drivers/media/usb/cx231xx/cx231xx-core.c +++ b/drivers/media/usb/cx231xx/cx231xx-core.c @@ -914,6 +914,7 @@ EXPORT_SYMBOL_GPL(cx231xx_uninit_isoc); */ void cx231xx_uninit_bulk(struct cx231xx *dev) { + struct cx231xx_dmaqueue *dma_q = &dev->video_mode.vidq; struct urb *urb; int i; @@ -931,7 +932,7 @@ void cx231xx_uninit_bulk(struct cx231xx *dev) if (dev->video_mode.bulk_ctl.transfer_buffer[i]) { usb_free_coherent(dev->udev, urb->transfer_buffer_length, - dev->video_mode.isoc_ctl. + dev->video_mode.bulk_ctl. transfer_buffer[i], urb->transfer_dma); } @@ -943,10 +944,12 @@ void cx231xx_uninit_bulk(struct cx231xx *dev) kfree(dev->video_mode.bulk_ctl.urb); kfree(dev->video_mode.bulk_ctl.transfer_buffer); + kfree(dma_q->p_left_data); dev->video_mode.bulk_ctl.urb = NULL; dev->video_mode.bulk_ctl.transfer_buffer = NULL; dev->video_mode.bulk_ctl.num_bufs = 0; + dma_q->p_left_data = NULL; if (dev->mode_tv == 0) cx231xx_capture_start(dev, 0, Raw_Video); @@ -1196,6 +1199,16 @@ int cx231xx_init_bulk(struct cx231xx *dev, int max_packets, sb_size, cx231xx_bulk_irq_callback, dma_q); } + /* clear halt */ + rc = usb_clear_halt(dev->udev, dev->video_mode.bulk_ctl.urb[0]->pipe); + if (rc < 0) { + dev_err(dev->dev, + "failed to clear USB bulk endpoint stall/halt condition (error=%i)\n", + rc); + cx231xx_uninit_bulk(dev); + return rc; + } + init_waitqueue_head(&dma_q->wq); /* submit urbs and enables IRQ */ diff --git a/drivers/media/usb/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c index 66ee161fc..b8d5b2be9 100644 --- a/drivers/media/usb/cx231xx/cx231xx-dvb.c +++ b/drivers/media/usb/cx231xx/cx231xx-dvb.c @@ -551,10 +551,14 @@ static int register_dvb(struct cx231xx_dvb *dvb, /* register network adapter */ dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx); - dvb_create_media_graph(&dvb->adapter); + result = dvb_create_media_graph(&dvb->adapter, false); + if (result < 0) + goto fail_create_graph; return 0; +fail_create_graph: + dvb_net_release(&dvb->net); fail_fe_conn: dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); fail_fe_mem: @@ -725,7 +729,7 @@ static int dvb_init(struct cx231xx *dev) dev->dvb->frontend = dvb_attach(lgdt3305_attach, &hcw_lgdt3305_config, - tuner_i2c); + demod_i2c); if (dev->dvb->frontend == NULL) { dev_err(dev->dev, @@ -746,7 +750,7 @@ static int dvb_init(struct cx231xx *dev) dev->dvb->frontend = dvb_attach(si2165_attach, &hauppauge_930C_HD_1113xx_si2165_config, - tuner_i2c + demod_i2c ); if (dev->dvb->frontend == NULL) { @@ -779,7 +783,7 @@ static int dvb_init(struct cx231xx *dev) dev->dvb->frontend = dvb_attach(si2165_attach, &pctv_quatro_stick_1114xx_si2165_config, - tuner_i2c + demod_i2c ); if (dev->dvb->frontend == NULL) { @@ -835,7 +839,7 @@ static int dvb_init(struct cx231xx *dev) dev->dvb->frontend = dvb_attach(lgdt3306a_attach, &hauppauge_955q_lgdt3306a_config, - tuner_i2c + demod_i2c ); if (dev->dvb->frontend == NULL) { diff --git a/drivers/media/usb/cx231xx/cx231xx-vbi.c b/drivers/media/usb/cx231xx/cx231xx-vbi.c index a08014d20..15bb573b7 100644 --- a/drivers/media/usb/cx231xx/cx231xx-vbi.c +++ b/drivers/media/usb/cx231xx/cx231xx-vbi.c @@ -32,7 +32,7 @@ #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> -#include <media/msp3400.h> +#include <media/drv-intf/msp3400.h> #include <media/tuner.h> #include "cx231xx-vbi.h" diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index d0d8f08e3..9b88cd812 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -36,7 +36,7 @@ #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> #include <media/v4l2-event.h> -#include <media/msp3400.h> +#include <media/drv-intf/msp3400.h> #include <media/tuner.h> #include "dvb_frontend.h" @@ -106,7 +106,7 @@ static int cx231xx_enable_analog_tuner(struct cx231xx *dev) struct media_device *mdev = dev->media_dev; struct media_entity *entity, *decoder = NULL, *source; struct media_link *link, *found_link = NULL; - int i, ret, active_links = 0; + int ret, active_links = 0; if (!mdev) return 0; @@ -119,7 +119,7 @@ static int cx231xx_enable_analog_tuner(struct cx231xx *dev) * this should be enough for the actual needs. */ media_device_for_each_entity(entity, mdev) { - if (entity->type == MEDIA_ENT_T_V4L2_SUBDEV_DECODER) { + if (entity->function == MEDIA_ENT_F_ATV_DECODER) { decoder = entity; break; } @@ -127,8 +127,7 @@ static int cx231xx_enable_analog_tuner(struct cx231xx *dev) if (!decoder) return 0; - for (i = 0; i < decoder->num_links; i++) { - link = &decoder->links[i]; + list_for_each_entry(link, &decoder->links, list) { if (link->sink->entity == decoder) { found_link = link; if (link->flags & MEDIA_LNK_FL_ENABLED) @@ -141,11 +140,10 @@ static int cx231xx_enable_analog_tuner(struct cx231xx *dev) return 0; source = found_link->source->entity; - for (i = 0; i < source->num_links; i++) { + list_for_each_entry(link, &source->links, list) { struct media_entity *sink; int flags = 0; - link = &source->links[i]; sink = link->sink->entity; if (sink == entity) @@ -1444,6 +1442,7 @@ static int vidioc_cropcap(struct file *file, void *priv, { struct cx231xx_fh *fh = priv; struct cx231xx *dev = fh->dev; + bool is_50hz = dev->norm & V4L2_STD_625_50; if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; @@ -1453,8 +1452,8 @@ static int vidioc_cropcap(struct file *file, void *priv, cc->bounds.width = dev->width; cc->bounds.height = dev->height; cc->defrect = cc->bounds; - cc->pixelaspect.numerator = 54; /* 4:3 FIXME: remove magic numbers */ - cc->pixelaspect.denominator = 59; + cc->pixelaspect.numerator = is_50hz ? 54 : 11; + cc->pixelaspect.denominator = is_50hz ? 59 : 10; return 0; } @@ -2176,7 +2175,7 @@ int cx231xx_register_analog_devices(struct cx231xx *dev) cx231xx_vdev_init(dev, &dev->vdev, &cx231xx_video_template, "video"); #if defined(CONFIG_MEDIA_CONTROLLER) dev->video_pad.flags = MEDIA_PAD_FL_SINK; - ret = media_entity_init(&dev->vdev.entity, 1, &dev->video_pad, 0); + ret = media_entity_pads_init(&dev->vdev.entity, 1, &dev->video_pad); if (ret < 0) dev_err(dev->dev, "failed to initialize video media entity!\n"); #endif @@ -2203,7 +2202,7 @@ int cx231xx_register_analog_devices(struct cx231xx *dev) #if defined(CONFIG_MEDIA_CONTROLLER) dev->vbi_pad.flags = MEDIA_PAD_FL_SINK; - ret = media_entity_init(&dev->vbi_dev.entity, 1, &dev->vbi_pad, 0); + ret = media_entity_pads_init(&dev->vbi_dev.entity, 1, &dev->vbi_pad); if (ret < 0) dev_err(dev->dev, "failed to initialize vbi media entity!\n"); #endif diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h index 54790fbe8..ec6d3f5bc 100644 --- a/drivers/media/usb/cx231xx/cx231xx.h +++ b/drivers/media/usb/cx231xx/cx231xx.h @@ -30,14 +30,14 @@ #include <linux/mutex.h> #include <linux/usb.h> -#include <media/cx2341x.h> +#include <media/drv-intf/cx2341x.h> #include <media/videobuf-vmalloc.h> #include <media/v4l2-device.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-fh.h> #include <media/rc-core.h> -#include <media/ir-kbd-i2c.h> +#include <media/i2c/ir-kbd-i2c.h> #include <media/videobuf-dvb.h> #include "cx231xx-reg.h" diff --git a/drivers/media/usb/dvb-usb-v2/Kconfig b/drivers/media/usb/dvb-usb-v2/Kconfig index 9facc92c8..3dc8ef004 100644 --- a/drivers/media/usb/dvb-usb-v2/Kconfig +++ b/drivers/media/usb/dvb-usb-v2/Kconfig @@ -9,7 +9,7 @@ config DVB_USB_V2 <file:Documentation/dvb/README.dvb-usb>. For a complete list of supported USB devices see the LinuxTV DVB Wiki: - <http://www.linuxtv.org/wiki/index.php/DVB_USB> + <https://linuxtv.org/wiki/index.php/DVB_USB> Say Y if you own a USB DVB device. diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c index b69500c2f..077a34c17 100644 --- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c @@ -400,17 +400,16 @@ skip_feed_stop: return ret; } -static void dvb_usbv2_media_device_register(struct dvb_usb_adapter *adap) +static int dvb_usbv2_media_device_init(struct dvb_usb_adapter *adap) { #ifdef CONFIG_MEDIA_CONTROLLER_DVB struct media_device *mdev; struct dvb_usb_device *d = adap_to_d(adap); struct usb_device *udev = d->udev; - int ret; mdev = kzalloc(sizeof(*mdev), GFP_KERNEL); if (!mdev) - return; + return -ENOMEM; mdev->dev = &udev->dev; strlcpy(mdev->model, d->name, sizeof(mdev->model)); @@ -420,19 +419,21 @@ static void dvb_usbv2_media_device_register(struct dvb_usb_adapter *adap) mdev->hw_revision = le16_to_cpu(udev->descriptor.bcdDevice); mdev->driver_version = LINUX_VERSION_CODE; - ret = media_device_register(mdev); - if (ret) { - dev_err(&d->udev->dev, - "Couldn't create a media device. Error: %d\n", - ret); - kfree(mdev); - return; - } + media_device_init(mdev); dvb_register_media_controller(&adap->dvb_adap, mdev); dev_info(&d->udev->dev, "media controller created\n"); +#endif + return 0; +} +static int dvb_usbv2_media_device_register(struct dvb_usb_adapter *adap) +{ +#ifdef CONFIG_MEDIA_CONTROLLER_DVB + return media_device_register(adap->dvb_adap.mdev); +#else + return 0; #endif } @@ -444,6 +445,7 @@ static void dvb_usbv2_media_device_unregister(struct dvb_usb_adapter *adap) return; media_device_unregister(adap->dvb_adap.mdev); + media_device_cleanup(adap->dvb_adap.mdev); kfree(adap->dvb_adap.mdev); adap->dvb_adap.mdev = NULL; @@ -467,7 +469,12 @@ static int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap) adap->dvb_adap.priv = adap; - dvb_usbv2_media_device_register(adap); + ret = dvb_usbv2_media_device_init(adap); + if (ret < 0) { + dev_dbg(&d->udev->dev, "%s: dvb_usbv2_media_device_init() failed=%d\n", + __func__, ret); + goto err_dvb_register_mc; + } if (d->props->read_mac_address) { ret = d->props->read_mac_address(adap, @@ -518,6 +525,7 @@ err_dvb_dmxdev_init: dvb_dmx_release(&adap->demux); err_dvb_dmx_init: dvb_usbv2_media_device_unregister(adap); +err_dvb_register_mc: dvb_unregister_adapter(&adap->dvb_adap); err_dvb_register_adapter: adap->dvb_adap.priv = NULL; @@ -534,7 +542,6 @@ static int dvb_usbv2_adapter_dvb_exit(struct dvb_usb_adapter *adap) adap->demux.dmx.close(&adap->demux.dmx); dvb_dmxdev_release(&adap->dmxdev); dvb_dmx_release(&adap->demux); - dvb_usbv2_media_device_unregister(adap); dvb_unregister_adapter(&adap->dvb_adap); } @@ -698,9 +705,13 @@ static int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap) } } - dvb_create_media_graph(&adap->dvb_adap); + ret = dvb_create_media_graph(&adap->dvb_adap, true); + if (ret < 0) + goto err_dvb_unregister_frontend; - return 0; + ret = dvb_usbv2_media_device_register(adap); + + return ret; err_dvb_unregister_frontend: for (i = count_registered - 1; i >= 0; i--) @@ -840,6 +851,7 @@ static int dvb_usbv2_adapter_exit(struct dvb_usb_device *d) dvb_usbv2_adapter_dvb_exit(&d->adapter[i]); dvb_usbv2_adapter_stream_exit(&d->adapter[i]); dvb_usbv2_adapter_frontend_exit(&d->adapter[i]); + dvb_usbv2_media_device_unregister(&d->adapter[i]); } } diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c index ea3753653..84f6de6fa 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c @@ -35,7 +35,7 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))."); struct mxl111sf_demod_state { struct mxl111sf_state *mxl_state; - struct mxl111sf_demod_config *cfg; + const struct mxl111sf_demod_config *cfg; struct dvb_frontend fe; }; @@ -579,7 +579,7 @@ static struct dvb_frontend_ops mxl111sf_demod_ops = { }; struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state, - struct mxl111sf_demod_config *cfg) + const struct mxl111sf_demod_config *cfg) { struct mxl111sf_demod_state *state = NULL; diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h index 0bd83e526..7065aca81 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h @@ -35,11 +35,11 @@ struct mxl111sf_demod_config { #if IS_ENABLED(CONFIG_DVB_USB_MXL111SF) extern struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state, - struct mxl111sf_demod_config *cfg); + const struct mxl111sf_demod_config *cfg); #else static inline struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state, - struct mxl111sf_demod_config *cfg) + const struct mxl111sf_demod_config *cfg) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf.c b/drivers/media/usb/dvb-usb-v2/mxl111sf.c index bec12b0e0..b669deccc 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf.c +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf.c @@ -10,6 +10,7 @@ #include <linux/vmalloc.h> #include <linux/i2c.h> +#include <media/tuner.h> #include "mxl111sf.h" #include "mxl111sf-reg.h" @@ -288,9 +289,9 @@ static int mxl111sf_adap_fe_init(struct dvb_frontend *fe) err = mxl1x1sf_set_device_mode(state, adap_state->device_mode); mxl_fail(err); - mxl111sf_enable_usb_output(state); + err = mxl111sf_enable_usb_output(state); mxl_fail(err); - mxl1x1sf_top_master_ctrl(state, 1); + err = mxl1x1sf_top_master_ctrl(state, 1); mxl_fail(err); if ((MXL111SF_GPIO_MOD_DVBT != adap_state->gpio_mode) && @@ -731,7 +732,7 @@ fail: return ret; } -static struct mxl111sf_demod_config mxl_demod_config = { +static const struct mxl111sf_demod_config mxl_demod_config = { .read_reg = mxl111sf_read_reg, .write_reg = mxl111sf_write_reg, .program_regs = mxl111sf_ctrl_program_regs, @@ -868,6 +869,10 @@ static struct mxl111sf_tuner_config mxl_tuner_config = { static int mxl111sf_attach_tuner(struct dvb_usb_adapter *adap) { struct mxl111sf_state *state = adap_to_priv(adap); +#ifdef CONFIG_MEDIA_CONTROLLER_DVB + struct media_device *mdev = dvb_get_media_controller(&adap->dvb_adap); + int ret; +#endif int i; pr_debug("%s()\n", __func__); @@ -879,6 +884,21 @@ static int mxl111sf_attach_tuner(struct dvb_usb_adapter *adap) adap->fe[i]->ops.read_signal_strength = adap->fe[i]->ops.tuner_ops.get_rf_strength; } +#ifdef CONFIG_MEDIA_CONTROLLER_DVB + state->tuner.function = MEDIA_ENT_F_TUNER; + state->tuner.name = "mxl111sf tuner"; + state->tuner_pads[TUNER_PAD_RF_INPUT].flags = MEDIA_PAD_FL_SINK; + state->tuner_pads[TUNER_PAD_IF_OUTPUT].flags = MEDIA_PAD_FL_SOURCE; + + ret = media_entity_pads_init(&state->tuner, + TUNER_NUM_PADS, state->tuner_pads); + if (ret) + return ret; + + ret = media_device_register_entity(mdev, &state->tuner); + if (ret) + return ret; +#endif return 0; } diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf.h b/drivers/media/usb/dvb-usb-v2/mxl111sf.h index ee70df1f1..846260e0e 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf.h +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf.h @@ -17,6 +17,7 @@ #define DVB_USB_LOG_PREFIX "mxl111sf" #include "dvb_usb.h" #include <media/tveeprom.h> +#include <media/media-entity.h> #define MXL_EP1_REG_READ 1 #define MXL_EP2_REG_WRITE 2 @@ -85,6 +86,10 @@ struct mxl111sf_state { struct mutex fe_lock; u8 num_frontends; struct mxl111sf_adap_state adap_state[3]; +#ifdef CONFIG_MEDIA_CONTROLLER_DVB + struct media_entity tuner; + struct media_pad tuner_pads[2]; +#endif }; int mxl111sf_read_reg(struct mxl111sf_state *state, u8 addr, u8 *data); diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c index 5a503a6bb..eb5787a31 100644 --- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c @@ -181,11 +181,17 @@ static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], goto err_mutex_unlock; } else if (msg[0].addr == 0x10) { /* method 1 - integrated demod */ - req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1); - req.index = CMD_DEMOD_RD | dev->page; - req.size = msg[1].len; - req.data = &msg[1].buf[0]; - ret = rtl28xxu_ctrl_msg(d, &req); + if (msg[0].buf[0] == 0x00) { + /* return demod page from driver cache */ + msg[1].buf[0] = dev->page; + ret = 0; + } else { + req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1); + req.index = CMD_DEMOD_RD | dev->page; + req.size = msg[1].len; + req.data = &msg[1].buf[0]; + ret = rtl28xxu_ctrl_msg(d, &req); + } } else if (msg[0].len < 2) { /* method 2 - old I2C */ req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1); diff --git a/drivers/media/usb/dvb-usb/Kconfig b/drivers/media/usb/dvb-usb/Kconfig index 128eee615..f03b0b70c 100644 --- a/drivers/media/usb/dvb-usb/Kconfig +++ b/drivers/media/usb/dvb-usb/Kconfig @@ -9,7 +9,7 @@ config DVB_USB <file:Documentation/dvb/README.dvb-usb>. For a complete list of supported USB devices see the LinuxTV DVB Wiki: - <http://www.linuxtv.org/wiki/index.php/DVB_USB> + <https://linuxtv.org/wiki/index.php/DVB_USB> Say Y if you own a USB DVB device. diff --git a/drivers/media/usb/dvb-usb/dvb-usb-dvb.c b/drivers/media/usb/dvb-usb/dvb-usb-dvb.c index 8a260c854..9ddfcab26 100644 --- a/drivers/media/usb/dvb-usb/dvb-usb-dvb.c +++ b/drivers/media/usb/dvb-usb/dvb-usb-dvb.c @@ -95,17 +95,16 @@ static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) return dvb_usb_ctrl_feed(dvbdmxfeed, 0); } -static void dvb_usb_media_device_register(struct dvb_usb_adapter *adap) +static int dvb_usb_media_device_init(struct dvb_usb_adapter *adap) { #ifdef CONFIG_MEDIA_CONTROLLER_DVB struct media_device *mdev; struct dvb_usb_device *d = adap->dev; struct usb_device *udev = d->udev; - int ret; mdev = kzalloc(sizeof(*mdev), GFP_KERNEL); if (!mdev) - return; + return -ENOMEM; mdev->dev = &udev->dev; strlcpy(mdev->model, d->desc->name, sizeof(mdev->model)); @@ -115,18 +114,22 @@ static void dvb_usb_media_device_register(struct dvb_usb_adapter *adap) mdev->hw_revision = le16_to_cpu(udev->descriptor.bcdDevice); mdev->driver_version = LINUX_VERSION_CODE; - ret = media_device_register(mdev); - if (ret) { - dev_err(&d->udev->dev, - "Couldn't create a media device. Error: %d\n", - ret); - kfree(mdev); - return; - } + media_device_init(mdev); + dvb_register_media_controller(&adap->dvb_adap, mdev); dev_info(&d->udev->dev, "media controller created\n"); #endif + return 0; +} + +static int dvb_usb_media_device_register(struct dvb_usb_adapter *adap) +{ +#ifdef CONFIG_MEDIA_CONTROLLER_DVB + return media_device_register(adap->dvb_adap.mdev); +#else + return 0; +#endif } static void dvb_usb_media_device_unregister(struct dvb_usb_adapter *adap) @@ -136,6 +139,7 @@ static void dvb_usb_media_device_unregister(struct dvb_usb_adapter *adap) return; media_device_unregister(adap->dvb_adap.mdev); + media_device_cleanup(adap->dvb_adap.mdev); kfree(adap->dvb_adap.mdev); adap->dvb_adap.mdev = NULL; #endif @@ -154,7 +158,11 @@ int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap, short *adapter_nums) } adap->dvb_adap.priv = adap; - dvb_usb_media_device_register(adap); + ret = dvb_usb_media_device_init(adap); + if (ret < 0) { + deb_info("dvb_usb_media_device_init failed: error %d", ret); + goto err_mc; + } if (adap->dev->props.read_mac_address) { if (adap->dev->props.read_mac_address(adap->dev, adap->dvb_adap.proposed_mac) == 0) @@ -204,6 +212,7 @@ err_dmx_dev: dvb_dmx_release(&adap->demux); err_dmx: dvb_usb_media_device_unregister(adap); +err_mc: dvb_unregister_adapter(&adap->dvb_adap); err: return ret; @@ -318,10 +327,16 @@ int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap) adap->num_frontends_initialized++; } + if (ret) + return ret; - dvb_create_media_graph(&adap->dvb_adap); + ret = dvb_create_media_graph(&adap->dvb_adap, true); + if (ret) + return ret; - return 0; + ret = dvb_usb_media_device_register(adap); + + return ret; } int dvb_usb_adapter_frontend_exit(struct dvb_usb_adapter *adap) diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c index ed0b3a879..b58acd3fc 100644 --- a/drivers/media/usb/em28xx/em28xx-camera.c +++ b/drivers/media/usb/em28xx/em28xx-camera.c @@ -21,7 +21,7 @@ #include <linux/i2c.h> #include <media/soc_camera.h> -#include <media/mt9v011.h> +#include <media/i2c/mt9v011.h> #include <media/v4l2-clk.h> #include <media/v4l2-common.h> @@ -322,7 +322,7 @@ int em28xx_detect_sensor(struct em28xx *dev) int em28xx_init_camera(struct em28xx *dev) { - char clk_name[V4L2_SUBDEV_NAME_SIZE]; + char clk_name[V4L2_CLK_NAME_SIZE]; struct i2c_client *client = &dev->i2c_client[dev->def_i2c_bus]; struct i2c_adapter *adap = &dev->i2c_adap[dev->def_i2c_bus]; struct em28xx_v4l2 *v4l2 = dev->v4l2; diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index ffa284ab8..69d75e0cd 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -30,10 +30,10 @@ #include <linux/i2c.h> #include <linux/usb.h> #include <media/tuner.h> -#include <media/msp3400.h> -#include <media/saa7115.h> -#include <media/tvp5150.h> -#include <media/tvaudio.h> +#include <media/drv-intf/msp3400.h> +#include <media/i2c/saa7115.h> +#include <media/i2c/tvp5150.h> +#include <media/i2c/tvaudio.h> #include <media/i2c-addr.h> #include <media/tveeprom.h> #include <media/v4l2-common.h> @@ -1051,8 +1051,12 @@ struct em28xx_board em28xx_boards[] = { }, [EM2870_BOARD_TERRATEC_XS_MT2060] = { .name = "Terratec Cinergy T XS (MT2060)", - .valid = EM28XX_BOARD_NOT_VALIDATED, + .xclk = EM28XX_XCLK_IR_RC5_MODE | + EM28XX_XCLK_FREQUENCY_12MHZ, + .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE, .tuner_type = TUNER_ABSENT, /* MT2060 */ + .has_dvb = 1, + .tuner_gpio = default_tuner_gpio, }, [EM2870_BOARD_KWORLD_350U] = { .name = "Kworld 350 U DVB-T", @@ -2368,7 +2372,7 @@ struct usb_device_id em28xx_id_table[] = { { USB_DEVICE(0x0ccd, 0x0042), .driver_info = EM2882_BOARD_TERRATEC_HYBRID_XS }, { USB_DEVICE(0x0ccd, 0x0043), - .driver_info = EM2870_BOARD_TERRATEC_XS }, + .driver_info = EM2870_BOARD_TERRATEC_XS_MT2060 }, { USB_DEVICE(0x0ccd, 0x008e), /* Cinergy HTC USB XS Rev. 1 */ .driver_info = EM2884_BOARD_TERRATEC_HTC_USB_XS }, { USB_DEVICE(0x0ccd, 0x00ac), /* Cinergy HTC USB XS Rev. 2 */ @@ -2471,6 +2475,8 @@ struct usb_device_id em28xx_id_table[] = { .driver_info = EM28178_BOARD_PCTV_461E }, { USB_DEVICE(0x2013, 0x025f), .driver_info = EM28178_BOARD_PCTV_292E }, + { USB_DEVICE(0x2040, 0x0264), /* Hauppauge WinTV-soloHD */ + .driver_info = EM28178_BOARD_PCTV_292E }, { USB_DEVICE(0x0413, 0x6f07), .driver_info = EM2861_BOARD_LEADTEK_VC100 }, { USB_DEVICE(0xeb1a, 0x8179), diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index 70b23d987..ae88f75f0 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c @@ -38,6 +38,7 @@ #include "lgdt3305.h" #include "zl10353.h" #include "s5h1409.h" +#include "mt2060.h" #include "mt352.h" #include "mt352_priv.h" /* FIXME */ #include "tda1002x.h" @@ -815,6 +816,10 @@ static struct zl10353_config em28xx_zl10353_no_i2c_gate_dev = { .parallel_ts = 1, }; +static struct mt2060_config em28xx_mt2060_config = { + .i2c_address = 0x60, +}; + static struct qt1010_config em28xx_qt1010_config = { .i2c_address = 0x62 }; @@ -1142,6 +1147,16 @@ static int em28xx_dvb_init(struct em28xx *dev) goto out_free; } break; + case EM2870_BOARD_TERRATEC_XS_MT2060: + dvb->fe[0] = dvb_attach(zl10353_attach, + &em28xx_zl10353_no_i2c_gate_dev, + &dev->i2c_adap[dev->def_i2c_bus]); + if (dvb->fe[0] != NULL) { + dvb_attach(mt2060_attach, dvb->fe[0], + &dev->i2c_adap[dev->def_i2c_bus], + &em28xx_mt2060_config, 1220); + } + break; case EM2870_BOARD_KWORLD_355U: dvb->fe[0] = dvb_attach(zl10353_attach, &em28xx_zl10353_no_i2c_gate_dev, diff --git a/drivers/media/usb/em28xx/em28xx-vbi.c b/drivers/media/usb/em28xx/em28xx-vbi.c index e23c285b3..fe94c9225 100644 --- a/drivers/media/usb/em28xx/em28xx-vbi.c +++ b/drivers/media/usb/em28xx/em28xx-vbi.c @@ -31,26 +31,22 @@ /* ------------------------------------------------------------------ */ -static int vbi_queue_setup(struct vb2_queue *vq, const void *parg, +static int vbi_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) { - const struct v4l2_format *fmt = parg; struct em28xx *dev = vb2_get_drv_priv(vq); struct em28xx_v4l2 *v4l2 = dev->v4l2; - unsigned long size; + unsigned long size = v4l2->vbi_width * v4l2->vbi_height * 2; - if (fmt) - size = fmt->fmt.pix.sizeimage; - else - size = v4l2->vbi_width * v4l2->vbi_height * 2; - - if (0 == *nbuffers) - *nbuffers = 32; if (*nbuffers < 2) *nbuffers = 2; - if (*nbuffers > 32) - *nbuffers = 32; + + if (*nplanes) { + if (sizes[0] < size) + return -EINVAL; + size = sizes[0]; + } *nplanes = 1; sizes[0] = size; diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 6a3cf342e..0e86ff423 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -43,7 +43,7 @@ #include <media/v4l2-ioctl.h> #include <media/v4l2-event.h> #include <media/v4l2-clk.h> -#include <media/msp3400.h> +#include <media/drv-intf/msp3400.h> #include <media/tuner.h> #define DRIVER_AUTHOR "Ludovico Cavedon <cavedon@sssup.it>, " \ @@ -438,7 +438,7 @@ static inline void finish_buffer(struct em28xx *dev, buf->vb.field = V4L2_FIELD_NONE; else buf->vb.field = V4L2_FIELD_INTERLACED; - v4l2_get_timestamp(&buf->vb.timestamp); + buf->vb.vb2_buf.timestamp = ktime_get_ns(); vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE); } @@ -871,30 +871,19 @@ static void res_free(struct em28xx *dev, enum v4l2_buf_type f_type) Videobuf2 operations ------------------------------------------------------------------*/ -static int queue_setup(struct vb2_queue *vq, const void *parg, +static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) { - const struct v4l2_format *fmt = parg; struct em28xx *dev = vb2_get_drv_priv(vq); struct em28xx_v4l2 *v4l2 = dev->v4l2; - unsigned long size; - - if (fmt) - size = fmt->fmt.pix.sizeimage; - else - size = + unsigned long size = (v4l2->width * v4l2->height * v4l2->format->depth + 7) >> 3; - if (size == 0) - return -EINVAL; - - if (0 == *nbuffers) - *nbuffers = 32; - + if (*nplanes) + return sizes[0] < size ? -EINVAL : 0; *nplanes = 1; sizes[0] = size; - return 0; } diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index 76bf8ba37..8ff066c97 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -40,7 +40,7 @@ #include <media/v4l2-device.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-fh.h> -#include <media/ir-kbd-i2c.h> +#include <media/i2c/ir-kbd-i2c.h> #include <media/rc-core.h> #include "tuner-xc2028.h" #include "xc5000.h" diff --git a/drivers/media/usb/go7007/go7007-driver.c b/drivers/media/usb/go7007/go7007-driver.c index a40174626..c090429a1 100644 --- a/drivers/media/usb/go7007/go7007-driver.c +++ b/drivers/media/usb/go7007/go7007-driver.c @@ -466,7 +466,7 @@ static struct go7007_buffer *frame_boundary(struct go7007 *go, struct go7007_buf else go7007_set_motion_regions(go, vb, 0); - v4l2_get_timestamp(&vb->vb.timestamp); + vb->vb.vb2_buf.timestamp = ktime_get_ns(); vb_tmp = vb; spin_lock(&go->spinlock); list_del(&vb->list); diff --git a/drivers/media/usb/go7007/go7007-usb.c b/drivers/media/usb/go7007/go7007-usb.c index 4857c467e..3dbf14c85 100644 --- a/drivers/media/usb/go7007/go7007-usb.c +++ b/drivers/media/usb/go7007/go7007-usb.c @@ -23,9 +23,9 @@ #include <linux/usb.h> #include <linux/i2c.h> #include <asm/byteorder.h> -#include <media/saa7115.h> +#include <media/i2c/saa7115.h> #include <media/tuner.h> -#include <media/uda1342.h> +#include <media/i2c/uda1342.h> #include "go7007-priv.h" @@ -1289,7 +1289,7 @@ static int go7007_usb_probe(struct usb_interface *intf, /* Allocate the URBs and buffers for receiving the audio stream */ if ((board->flags & GO7007_USB_EZUSB) && - (board->flags & GO7007_BOARD_HAS_AUDIO)) { + (board->main_info.flags & GO7007_BOARD_HAS_AUDIO)) { for (i = 0; i < 8; ++i) { usb->audio_urbs[i] = usb_alloc_urb(0, GFP_KERNEL); if (usb->audio_urbs[i] == NULL) diff --git a/drivers/media/usb/go7007/go7007-v4l2.c b/drivers/media/usb/go7007/go7007-v4l2.c index f3d187db9..358c1c186 100644 --- a/drivers/media/usb/go7007/go7007-v4l2.c +++ b/drivers/media/usb/go7007/go7007-v4l2.c @@ -30,7 +30,7 @@ #include <media/v4l2-subdev.h> #include <media/v4l2-event.h> #include <media/videobuf2-vmalloc.h> -#include <media/saa7115.h> +#include <media/i2c/saa7115.h> #include "go7007-priv.h" @@ -369,7 +369,6 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, } static int go7007_queue_setup(struct vb2_queue *q, - const void *parg, unsigned int *num_buffers, unsigned int *num_planes, unsigned int sizes[], void *alloc_ctxs[]) { diff --git a/drivers/media/usb/hackrf/hackrf.c b/drivers/media/usb/hackrf/hackrf.c index 0fe5cb2c2..9e700caf0 100644 --- a/drivers/media/usb/hackrf/hackrf.c +++ b/drivers/media/usb/hackrf/hackrf.c @@ -526,7 +526,7 @@ static void hackrf_urb_complete_in(struct urb *urb) urb->transfer_buffer, len); vb2_set_plane_payload(&buffer->vb.vb2_buf, 0, len); buffer->vb.sequence = dev->sequence++; - v4l2_get_timestamp(&buffer->vb.timestamp); + buffer->vb.vb2_buf.timestamp = ktime_get_ns(); vb2_buffer_done(&buffer->vb.vb2_buf, VB2_BUF_STATE_DONE); exit_usb_submit_urb: usb_submit_urb(urb, GFP_ATOMIC); @@ -571,7 +571,7 @@ static void hackrf_urb_complete_out(struct urb *urb) vb2_plane_vaddr(&buffer->vb.vb2_buf, 0), len); urb->actual_length = len; buffer->vb.sequence = dev->sequence++; - v4l2_get_timestamp(&buffer->vb.timestamp); + buffer->vb.vb2_buf.timestamp = ktime_get_ns(); vb2_buffer_done(&buffer->vb.vb2_buf, VB2_BUF_STATE_DONE); exit_usb_submit_urb: usb_submit_urb(urb, GFP_ATOMIC); @@ -759,7 +759,7 @@ static void hackrf_return_all_buffers(struct vb2_queue *vq, } static int hackrf_queue_setup(struct vb2_queue *vq, - const void *parg, unsigned int *nbuffers, + unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) { struct hackrf_dev *dev = vb2_get_drv_priv(vq); diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c index d8d8c0f51..7dee22dee 100644 --- a/drivers/media/usb/hdpvr/hdpvr-video.c +++ b/drivers/media/usb/hdpvr/hdpvr-video.c @@ -642,7 +642,7 @@ static int vidioc_s_dv_timings(struct file *file, void *_fh, if (dev->status != STATUS_IDLE) return -EBUSY; for (i = 0; i < ARRAY_SIZE(hdpvr_dv_timings); i++) - if (v4l2_match_dv_timings(timings, hdpvr_dv_timings + i, 0)) + if (v4l2_match_dv_timings(timings, hdpvr_dv_timings + i, 0, false)) break; if (i == ARRAY_SIZE(hdpvr_dv_timings)) return -EINVAL; diff --git a/drivers/media/usb/hdpvr/hdpvr.h b/drivers/media/usb/hdpvr/hdpvr.h index a31943041..78e815441 100644 --- a/drivers/media/usb/hdpvr/hdpvr.h +++ b/drivers/media/usb/hdpvr/hdpvr.h @@ -17,7 +17,7 @@ #include <media/v4l2-device.h> #include <media/v4l2-ctrls.h> -#include <media/ir-kbd-i2c.h> +#include <media/i2c/ir-kbd-i2c.h> #define HDPVR_MAX 8 #define HDPVR_I2C_MAX_SIZE 128 diff --git a/drivers/media/usb/msi2500/msi2500.c b/drivers/media/usb/msi2500/msi2500.c index e06a21a4f..c104315fd 100644 --- a/drivers/media/usb/msi2500/msi2500.c +++ b/drivers/media/usb/msi2500/msi2500.c @@ -616,7 +616,6 @@ static int msi2500_querycap(struct file *file, void *fh, /* Videobuf2 operations */ static int msi2500_queue_setup(struct vb2_queue *vq, - const void *parg, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) diff --git a/drivers/media/usb/pvrusb2/pvrusb2-audio.c b/drivers/media/usb/pvrusb2/pvrusb2-audio.c index 45276c628..5f953d837 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-audio.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-audio.c @@ -23,7 +23,7 @@ #include "pvrusb2-hdw-internal.h" #include "pvrusb2-debug.h" #include <linux/videodev2.h> -#include <media/msp3400.h> +#include <media/drv-intf/msp3400.h> #include <media/v4l2-common.h> diff --git a/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c b/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c index 1a81aa705..7d675fae1 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c @@ -32,7 +32,7 @@ #include "pvrusb2-hdw-internal.h" #include "pvrusb2-debug.h" -#include <media/cx25840.h> +#include <media/drv-intf/cx25840.h> #include <linux/videodev2.h> #include <media/v4l2-common.h> #include <linux/errno.h> diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/usb/pvrusb2/pvrusb2-hdw-internal.h index 1f9c02801..60141b16d 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-hdw-internal.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw-internal.h @@ -39,8 +39,8 @@ #include "pvrusb2-hdw.h" #include "pvrusb2-io.h" #include <media/v4l2-device.h> -#include <media/cx2341x.h> -#include <media/ir-kbd-i2c.h> +#include <media/drv-intf/cx2341x.h> +#include <media/i2c/ir-kbd-i2c.h> #include "pvrusb2-devattr.h" /* Legal values for PVR2_CID_HSM */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c index 4baa9d632..14321d0a1 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c @@ -20,7 +20,7 @@ #include <linux/i2c.h> #include <linux/module.h> -#include <media/ir-kbd-i2c.h> +#include <media/i2c/ir-kbd-i2c.h> #include "pvrusb2-i2c-core.h" #include "pvrusb2-hdw-internal.h" #include "pvrusb2-debug.h" diff --git a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c index 1c5f85bf7..81f788b7b 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c @@ -628,6 +628,7 @@ static int pvr2_g_ext_ctrls(struct file *file, void *priv, struct pvr2_v4l2_fh *fh = file->private_data; struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; struct v4l2_ext_control *ctrl; + struct pvr2_ctrl *cptr; unsigned int idx; int val; int ret; @@ -635,8 +636,15 @@ static int pvr2_g_ext_ctrls(struct file *file, void *priv, ret = 0; for (idx = 0; idx < ctls->count; idx++) { ctrl = ctls->controls + idx; - ret = pvr2_ctrl_get_value( - pvr2_hdw_get_ctrl_v4l(hdw, ctrl->id), &val); + cptr = pvr2_hdw_get_ctrl_v4l(hdw, ctrl->id); + if (cptr) { + if (ctls->which == V4L2_CTRL_WHICH_DEF_VAL) + pvr2_ctrl_get_def(cptr, &val); + else + ret = pvr2_ctrl_get_value(cptr, &val); + } else + ret = -EINVAL; + if (ret) { ctls->error_idx = idx; return ret; @@ -658,6 +666,10 @@ static int pvr2_s_ext_ctrls(struct file *file, void *priv, unsigned int idx; int ret; + /* Default value cannot be changed */ + if (ctls->which == V4L2_CTRL_WHICH_DEF_VAL) + return -EINVAL; + ret = 0; for (idx = 0; idx < ctls->count; idx++) { ctrl = ctls->controls + idx; diff --git a/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.c b/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.c index 139b39740..105123ab3 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.c @@ -35,7 +35,7 @@ #include "pvrusb2-debug.h" #include <linux/videodev2.h> #include <media/v4l2-common.h> -#include <media/saa7115.h> +#include <media/i2c/saa7115.h> #include <linux/errno.h> struct routing_scheme { diff --git a/drivers/media/usb/pwc/pwc-if.c b/drivers/media/usb/pwc/pwc-if.c index b79c36fd8..086cf1c7b 100644 --- a/drivers/media/usb/pwc/pwc-if.c +++ b/drivers/media/usb/pwc/pwc-if.c @@ -316,8 +316,7 @@ static void pwc_isoc_handler(struct urb *urb) struct pwc_frame_buf *fbuf = pdev->fill_buf; if (pdev->vsync == 1) { - v4l2_get_timestamp( - &fbuf->vb.timestamp); + fbuf->vb.vb2_buf.timestamp = ktime_get_ns(); pdev->vsync = 2; } @@ -571,7 +570,7 @@ static void pwc_video_release(struct v4l2_device *v) /***************************************************************************/ /* Videobuf2 operations */ -static int queue_setup(struct vb2_queue *vq, const void *parg, +static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) { diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index b96e02e8b..66b97da7d 100644 --- a/drivers/media/usb/s2255/s2255drv.c +++ b/drivers/media/usb/s2255/s2255drv.c @@ -574,7 +574,7 @@ static void s2255_got_frame(struct s2255_vc *vc, int jpgsize) buf = list_entry(vc->buf_list.next, struct s2255_buffer, list); list_del(&buf->list); - v4l2_get_timestamp(&buf->vb.timestamp); + buf->vb.vb2_buf.timestamp = ktime_get_ns(); buf->vb.field = vc->field; buf->vb.sequence = vc->frame_count; spin_unlock_irqrestore(&vc->qlock, flags); @@ -660,7 +660,7 @@ static void s2255_fillbuff(struct s2255_vc *vc, Videobuf operations ------------------------------------------------------------------*/ -static int queue_setup(struct vb2_queue *vq, const void *parg, +static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) { diff --git a/drivers/media/usb/siano/smsusb.c b/drivers/media/usb/siano/smsusb.c index cb2753930..7ef205700 100644 --- a/drivers/media/usb/siano/smsusb.c +++ b/drivers/media/usb/siano/smsusb.c @@ -361,10 +361,11 @@ static void *siano_media_device_register(struct smsusb_device_t *dev, mdev->hw_revision = le16_to_cpu(udev->descriptor.bcdDevice); mdev->driver_version = LINUX_VERSION_CODE; + media_device_init(mdev); + ret = media_device_register(mdev); if (ret) { - pr_err("Couldn't create a media device. Error: %d\n", - ret); + media_device_cleanup(mdev); kfree(mdev); return NULL; } diff --git a/drivers/media/usb/stk1160/stk1160-core.c b/drivers/media/usb/stk1160/stk1160-core.c index 1b6836f15..bc0294780 100644 --- a/drivers/media/usb/stk1160/stk1160-core.c +++ b/drivers/media/usb/stk1160/stk1160-core.c @@ -34,7 +34,7 @@ #include <linux/usb.h> #include <linux/mm.h> #include <linux/vmalloc.h> -#include <media/saa7115.h> +#include <media/i2c/saa7115.h> #include "stk1160.h" #include "stk1160-reg.h" diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c index 0bd34f1e7..77131fd61 100644 --- a/drivers/media/usb/stk1160/stk1160-v4l.c +++ b/drivers/media/usb/stk1160/stk1160-v4l.c @@ -33,7 +33,7 @@ #include <media/v4l2-event.h> #include <media/videobuf2-vmalloc.h> -#include <media/saa7115.h> +#include <media/i2c/saa7115.h> #include "stk1160.h" #include "stk1160-reg.h" @@ -664,7 +664,7 @@ static const struct v4l2_ioctl_ops stk1160_ioctl_ops = { /* * Videobuf2 operations */ -static int queue_setup(struct vb2_queue *vq, const void *parg, +static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) { diff --git a/drivers/media/usb/stk1160/stk1160-video.c b/drivers/media/usb/stk1160/stk1160-video.c index 75654e676..46191d526 100644 --- a/drivers/media/usb/stk1160/stk1160-video.c +++ b/drivers/media/usb/stk1160/stk1160-video.c @@ -99,7 +99,7 @@ void stk1160_buffer_done(struct stk1160 *dev) buf->vb.sequence = dev->sequence++; buf->vb.field = V4L2_FIELD_INTERLACED; buf->vb.vb2_buf.planes[0].bytesused = buf->bytesused; - v4l2_get_timestamp(&buf->vb.timestamp); + buf->vb.vb2_buf.timestamp = ktime_get_ns(); vb2_set_plane_payload(&buf->vb.vb2_buf, 0, buf->bytesused); vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE); diff --git a/drivers/media/usb/tm6000/tm6000-cards.c b/drivers/media/usb/tm6000/tm6000-cards.c index 243044434..7236daac1 100644 --- a/drivers/media/usb/tm6000/tm6000-cards.c +++ b/drivers/media/usb/tm6000/tm6000-cards.c @@ -26,7 +26,7 @@ #include <linux/slab.h> #include <media/v4l2-common.h> #include <media/tuner.h> -#include <media/tvaudio.h> +#include <media/i2c/tvaudio.h> #include <media/i2c-addr.h> #include <media/rc-map.h> diff --git a/drivers/media/usb/ttusb-dec/ttusb_dec.c b/drivers/media/usb/ttusb-dec/ttusb_dec.c index 06aedcb8d..1e619b6e8 100644 --- a/drivers/media/usb/ttusb-dec/ttusb_dec.c +++ b/drivers/media/usb/ttusb-dec/ttusb_dec.c @@ -1606,7 +1606,7 @@ static int fe_send_command(struct dvb_frontend* fe, const u8 command, return ttusb_dec_send_command(dec, command, param_length, params, result_length, cmd_result); } -static struct ttusbdecfe_config fe_config = { +static const struct ttusbdecfe_config fe_config = { .send_command = fe_send_command }; diff --git a/drivers/media/usb/usbtv/usbtv-video.c b/drivers/media/usb/usbtv/usbtv-video.c index e645c9df2..4ebb33943 100644 --- a/drivers/media/usb/usbtv/usbtv-video.c +++ b/drivers/media/usb/usbtv/usbtv-video.c @@ -322,7 +322,7 @@ static void usbtv_image_chunk(struct usbtv *usbtv, __be32 *chunk) buf->vb.field = V4L2_FIELD_INTERLACED; buf->vb.sequence = usbtv->sequence++; - v4l2_get_timestamp(&buf->vb.timestamp); + buf->vb.vb2_buf.timestamp = ktime_get_ns(); vb2_set_plane_payload(&buf->vb.vb2_buf, 0, size); vb2_buffer_done(&buf->vb.vb2_buf, state); list_del(&buf->list); @@ -599,19 +599,18 @@ static struct v4l2_file_operations usbtv_fops = { }; static int usbtv_queue_setup(struct vb2_queue *vq, - const void *parg, unsigned int *nbuffers, + unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) { - const struct v4l2_format *fmt = parg; struct usbtv *usbtv = vb2_get_drv_priv(vq); unsigned size = USBTV_CHUNK * usbtv->n_chunks * 2 * sizeof(u32); if (vq->num_buffers + *nbuffers < 2) *nbuffers = 2 - vq->num_buffers; + if (*nplanes) + return sizes[0] < size ? -EINVAL : 0; *nplanes = 1; - if (fmt && fmt->fmt.pix.sizeimage < size) - return -EINVAL; - sizes[0] = fmt ? fmt->fmt.pix.sizeimage : size; + sizes[0] = size; return 0; } diff --git a/drivers/media/usb/usbvision/usbvision-core.c b/drivers/media/usb/usbvision/usbvision-core.c index dc3b4d515..1ea04e75f 100644 --- a/drivers/media/usb/usbvision/usbvision-core.c +++ b/drivers/media/usb/usbvision/usbvision-core.c @@ -37,7 +37,7 @@ #include <linux/videodev2.h> #include <linux/i2c.h> -#include <media/saa7115.h> +#include <media/i2c/saa7115.h> #include <media/v4l2-common.h> #include <media/tuner.h> diff --git a/drivers/media/usb/usbvision/usbvision-video.c b/drivers/media/usb/usbvision/usbvision-video.c index b693206f6..de9ff3bb8 100644 --- a/drivers/media/usb/usbvision/usbvision-video.c +++ b/drivers/media/usb/usbvision/usbvision-video.c @@ -59,7 +59,7 @@ #include <linux/videodev2.h> #include <linux/i2c.h> -#include <media/saa7115.h> +#include <media/i2c/saa7115.h> #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> #include <media/v4l2-event.h> @@ -1461,11 +1461,32 @@ static int usbvision_probe(struct usb_interface *intf, printk(KERN_INFO "%s: %s found\n", __func__, usbvision_device_data[model].model_string); + /* + * this is a security check. + * an exploit using an incorrect bInterfaceNumber is known + */ + if (ifnum >= USB_MAXINTERFACES || !dev->actconfig->interface[ifnum]) + return -ENODEV; + if (usbvision_device_data[model].interface >= 0) interface = &dev->actconfig->interface[usbvision_device_data[model].interface]->altsetting[0]; - else + else if (ifnum < dev->actconfig->desc.bNumInterfaces) interface = &dev->actconfig->interface[ifnum]->altsetting[0]; + else { + dev_err(&intf->dev, "interface %d is invalid, max is %d\n", + ifnum, dev->actconfig->desc.bNumInterfaces - 1); + ret = -ENODEV; + goto err_usb; + } + + if (interface->desc.bNumEndpoints < 2) { + dev_err(&intf->dev, "interface %d has %d endpoints, but must" + " have minimum 2\n", ifnum, interface->desc.bNumEndpoints); + ret = -ENODEV; + goto err_usb; + } endpoint = &interface->endpoint[1].desc; + if (!usb_endpoint_xfer_isoc(endpoint)) { dev_err(&intf->dev, "%s: interface %d. has non-ISO endpoint!\n", __func__, ifnum); diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c index 3e59b288b..c2ee6e39f 100644 --- a/drivers/media/usb/uvc/uvc_ctrl.c +++ b/drivers/media/usb/uvc/uvc_ctrl.c @@ -227,7 +227,8 @@ static struct uvc_control_info uvc_ctrls[] = { .size = 4, .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_RANGE - | UVC_CTRL_FLAG_RESTORE, + | UVC_CTRL_FLAG_RESTORE + | UVC_CTRL_FLAG_AUTO_UPDATE, }, { .entity = UVC_GUID_UVC_CAMERA, diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index d11fd6ac2..4e7148815 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -1656,6 +1656,7 @@ static void uvc_delete(struct uvc_device *dev) #ifdef CONFIG_MEDIA_CONTROLLER if (media_devnode_is_registered(&dev->mdev.devnode)) media_device_unregister(&dev->mdev); + media_device_cleanup(&dev->mdev); #endif list_for_each_safe(p, n, &dev->chains) { @@ -1906,7 +1907,7 @@ static int uvc_probe(struct usb_interface *intf, "linux-uvc-devel mailing list.\n"); } - /* Register the media and V4L2 devices. */ + /* Initialize the media device and register the V4L2 device. */ #ifdef CONFIG_MEDIA_CONTROLLER dev->mdev.dev = &intf->dev; strlcpy(dev->mdev.model, dev->name, sizeof(dev->mdev.model)); @@ -1916,8 +1917,7 @@ static int uvc_probe(struct usb_interface *intf, strcpy(dev->mdev.bus_info, udev->devpath); dev->mdev.hw_revision = le16_to_cpu(udev->descriptor.bcdDevice); dev->mdev.driver_version = LINUX_VERSION_CODE; - if (media_device_register(&dev->mdev) < 0) - goto error; + media_device_init(&dev->mdev); dev->vdev.mdev = &dev->mdev; #endif @@ -1936,6 +1936,11 @@ static int uvc_probe(struct usb_interface *intf, if (uvc_register_chains(dev) < 0) goto error; +#ifdef CONFIG_MEDIA_CONTROLLER + /* Register the media device node */ + if (media_device_register(&dev->mdev) < 0) + goto error; +#endif /* Save our data pointer in the interface data. */ usb_set_intfdata(intf, dev); @@ -2540,7 +2545,8 @@ static struct usb_device_id uvc_ids[] = { .bInterfaceProtocol = 0, .driver_info = UVC_QUIRK_FORCE_Y8 }, /* Generic USB Video Class */ - { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) }, + { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, UVC_PC_PROTOCOL_UNDEFINED) }, + { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, UVC_PC_PROTOCOL_15) }, {} }; diff --git a/drivers/media/usb/uvc/uvc_entity.c b/drivers/media/usb/uvc/uvc_entity.c index dc56a59ec..ac386bb54 100644 --- a/drivers/media/usb/uvc/uvc_entity.c +++ b/drivers/media/usb/uvc/uvc_entity.c @@ -19,12 +19,8 @@ #include "uvcvideo.h" -/* ------------------------------------------------------------------------ - * Video subdevices registration and unregistration - */ - -static int uvc_mc_register_entity(struct uvc_video_chain *chain, - struct uvc_entity *entity) +static int uvc_mc_create_links(struct uvc_video_chain *chain, + struct uvc_entity *entity) { const u32 flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE; struct media_entity *sink; @@ -56,16 +52,13 @@ static int uvc_mc_register_entity(struct uvc_video_chain *chain, continue; remote_pad = remote->num_pads - 1; - ret = media_entity_create_link(source, remote_pad, + ret = media_create_pad_link(source, remote_pad, sink, i, flags); if (ret < 0) return ret; } - if (UVC_ENTITY_TYPE(entity) == UVC_TT_STREAMING) - return 0; - - return v4l2_device_register_subdev(&chain->dev->vdev, &entity->subdev); + return 0; } static struct v4l2_subdev_ops uvc_subdev_ops = { @@ -79,7 +72,8 @@ void uvc_mc_cleanup_entity(struct uvc_entity *entity) media_entity_cleanup(&entity->vdev->entity); } -static int uvc_mc_init_entity(struct uvc_entity *entity) +static int uvc_mc_init_entity(struct uvc_video_chain *chain, + struct uvc_entity *entity) { int ret; @@ -88,11 +82,17 @@ static int uvc_mc_init_entity(struct uvc_entity *entity) strlcpy(entity->subdev.name, entity->name, sizeof(entity->subdev.name)); - ret = media_entity_init(&entity->subdev.entity, - entity->num_pads, entity->pads, 0); + ret = media_entity_pads_init(&entity->subdev.entity, + entity->num_pads, entity->pads); + + if (ret < 0) + return ret; + + ret = v4l2_device_register_subdev(&chain->dev->vdev, + &entity->subdev); } else if (entity->vdev != NULL) { - ret = media_entity_init(&entity->vdev->entity, - entity->num_pads, entity->pads, 0); + ret = media_entity_pads_init(&entity->vdev->entity, + entity->num_pads, entity->pads); if (entity->flags & UVC_ENTITY_FLAG_DEFAULT) entity->vdev->entity.flags |= MEDIA_ENT_FL_DEFAULT; } else @@ -107,7 +107,7 @@ int uvc_mc_register_entities(struct uvc_video_chain *chain) int ret; list_for_each_entry(entity, &chain->entities, chain) { - ret = uvc_mc_init_entity(entity); + ret = uvc_mc_init_entity(chain, entity); if (ret < 0) { uvc_printk(KERN_INFO, "Failed to initialize entity for " "entity %u\n", entity->id); @@ -116,9 +116,9 @@ int uvc_mc_register_entities(struct uvc_video_chain *chain) } list_for_each_entry(entity, &chain->entities, chain) { - ret = uvc_mc_register_entity(chain, entity); + ret = uvc_mc_create_links(chain, entity); if (ret < 0) { - uvc_printk(KERN_INFO, "Failed to register entity for " + uvc_printk(KERN_INFO, "Failed to create links for " "entity %u\n", entity->id); return ret; } diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c index cfb868a48..543947227 100644 --- a/drivers/media/usb/uvc/uvc_queue.c +++ b/drivers/media/usb/uvc/uvc_queue.c @@ -69,23 +69,19 @@ static void uvc_queue_return_buffers(struct uvc_video_queue *queue, * videobuf2 queue operations */ -static int uvc_queue_setup(struct vb2_queue *vq, const void *parg, +static int uvc_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) { - const struct v4l2_format *fmt = parg; struct uvc_video_queue *queue = vb2_get_drv_priv(vq); struct uvc_streaming *stream = uvc_queue_to_stream(queue); + unsigned size = stream->ctrl.dwMaxVideoFrameSize; /* Make sure the image size is large enough. */ - if (fmt && fmt->fmt.pix.sizeimage < stream->ctrl.dwMaxVideoFrameSize) - return -EINVAL; - + if (*nplanes) + return sizes[0] < size ? -EINVAL : 0; *nplanes = 1; - - sizes[0] = fmt ? fmt->fmt.pix.sizeimage - : stream->ctrl.dwMaxVideoFrameSize; - + sizes[0] = size; return 0; } diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index 2764f4360..d7723ce77 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c @@ -983,6 +983,22 @@ static int uvc_ioctl_g_ext_ctrls(struct file *file, void *fh, unsigned int i; int ret; + if (ctrls->which == V4L2_CTRL_WHICH_DEF_VAL) { + for (i = 0; i < ctrls->count; ++ctrl, ++i) { + struct v4l2_queryctrl qc = { .id = ctrl->id }; + + ret = uvc_query_v4l2_ctrl(chain, &qc); + if (ret < 0) { + ctrls->error_idx = i; + return ret; + } + + ctrl->value = qc.default_value; + } + + return 0; + } + ret = uvc_ctrl_begin(chain); if (ret < 0) return ret; @@ -1010,6 +1026,10 @@ static int uvc_ioctl_s_try_ext_ctrls(struct uvc_fh *handle, unsigned int i; int ret; + /* Default value cannot be changed */ + if (ctrls->which == V4L2_CTRL_WHICH_DEF_VAL) + return -EINVAL; + ret = uvc_ctrl_begin(chain); if (ret < 0) return ret; diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index 2b276ab77..075a0fe77 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -694,22 +694,19 @@ void uvc_video_clock_update(struct uvc_streaming *stream, ts.tv_nsec -= NSEC_PER_SEC; } - uvc_trace(UVC_TRACE_CLOCK, "%s: SOF %u.%06llu y %llu ts %lu.%06lu " - "buf ts %lu.%06lu (x1 %u/%u/%u x2 %u/%u/%u y1 %u y2 %u)\n", + uvc_trace(UVC_TRACE_CLOCK, "%s: SOF %u.%06llu y %llu ts %llu " + "buf ts %llu (x1 %u/%u/%u x2 %u/%u/%u y1 %u y2 %u)\n", stream->dev->name, sof >> 16, div_u64(((u64)sof & 0xffff) * 1000000LLU, 65536), - y, ts.tv_sec, ts.tv_nsec / NSEC_PER_USEC, - vbuf->timestamp.tv_sec, - (unsigned long)vbuf->timestamp.tv_usec, + y, timespec_to_ns(&ts), vbuf->vb2_buf.timestamp, x1, first->host_sof, first->dev_sof, x2, last->host_sof, last->dev_sof, y1, y2); /* Update the V4L2 buffer. */ - vbuf->timestamp.tv_sec = ts.tv_sec; - vbuf->timestamp.tv_usec = ts.tv_nsec / NSEC_PER_USEC; + vbuf->vb2_buf.timestamp = timespec_to_ns(&ts); done: - spin_unlock_irqrestore(&stream->clock.lock, flags); + spin_unlock_irqrestore(&clock->lock, flags); } /* ------------------------------------------------------------------------ @@ -1034,9 +1031,7 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, buf->buf.field = V4L2_FIELD_NONE; buf->buf.sequence = stream->sequence; - buf->buf.timestamp.tv_sec = ts.tv_sec; - buf->buf.timestamp.tv_usec = - ts.tv_nsec / NSEC_PER_USEC; + buf->buf.vb2_buf.timestamp = timespec_to_ns(&ts); /* TODO: Handle PTS and SCR. */ buf->state = UVC_BUF_STATE_ACTIVE; diff --git a/drivers/media/v4l2-core/tuner-core.c b/drivers/media/v4l2-core/tuner-core.c index 581e21ad6..76496fd28 100644 --- a/drivers/media/v4l2-core/tuner-core.c +++ b/drivers/media/v4l2-core/tuner-core.c @@ -134,8 +134,9 @@ struct tuner { unsigned int type; /* chip type id */ void *config; const char *name; + #if defined(CONFIG_MEDIA_CONTROLLER) - struct media_pad pad; + struct media_pad pad[TUNER_NUM_PADS]; #endif }; @@ -695,11 +696,12 @@ static int tuner_probe(struct i2c_client *client, /* Should be just before return */ register_client: #if defined(CONFIG_MEDIA_CONTROLLER) - t->pad.flags = MEDIA_PAD_FL_SOURCE; - t->sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV_TUNER; + t->pad[TUNER_PAD_RF_INPUT].flags = MEDIA_PAD_FL_SINK; + t->pad[TUNER_PAD_IF_OUTPUT].flags = MEDIA_PAD_FL_SOURCE; + t->sd.entity.function = MEDIA_ENT_F_TUNER; t->sd.entity.name = t->name; - ret = media_entity_init(&t->sd.entity, 1, &t->pad, 0); + ret = media_entity_pads_init(&t->sd.entity, TUNER_NUM_PADS, &t->pad[0]); if (ret < 0) { tuner_err("failed to initialize media entity!\n"); kfree(t); diff --git a/drivers/media/v4l2-core/v4l2-clk.c b/drivers/media/v4l2-core/v4l2-clk.c index 34e416a55..297e10e69 100644 --- a/drivers/media/v4l2-core/v4l2-clk.c +++ b/drivers/media/v4l2-core/v4l2-clk.c @@ -15,6 +15,7 @@ #include <linux/list.h> #include <linux/module.h> #include <linux/mutex.h> +#include <linux/of.h> #include <linux/slab.h> #include <linux/string.h> @@ -39,6 +40,7 @@ struct v4l2_clk *v4l2_clk_get(struct device *dev, const char *id) { struct v4l2_clk *clk; struct clk *ccf_clk = clk_get(dev, id); + char clk_name[V4L2_CLK_NAME_SIZE]; if (PTR_ERR(ccf_clk) == -EPROBE_DEFER) return ERR_PTR(-EPROBE_DEFER); @@ -57,6 +59,13 @@ struct v4l2_clk *v4l2_clk_get(struct device *dev, const char *id) mutex_lock(&clk_lock); clk = v4l2_clk_find(dev_name(dev)); + /* if dev_name is not found, try use the OF name to find again */ + if (PTR_ERR(clk) == -ENODEV && dev->of_node) { + v4l2_clk_name_of(clk_name, sizeof(clk_name), + of_node_full_name(dev->of_node)); + clk = v4l2_clk_find(clk_name); + } + if (!IS_ERR(clk)) atomic_inc(&clk->use_count); mutex_unlock(&clk_lock); diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 327e83ac2..8fd84a674 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -630,7 +630,7 @@ static inline int put_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __ } struct v4l2_ext_controls32 { - __u32 ctrl_class; + __u32 which; __u32 count; __u32 error_idx; __u32 reserved[2]; @@ -673,7 +673,7 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext compat_caddr_t p; if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_ext_controls32)) || - get_user(kp->ctrl_class, &up->ctrl_class) || + get_user(kp->which, &up->which) || get_user(kp->count, &up->count) || get_user(kp->error_idx, &up->error_idx) || copy_from_user(kp->reserved, up->reserved, @@ -723,7 +723,7 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext compat_caddr_t p; if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_ext_controls32)) || - put_user(kp->ctrl_class, &up->ctrl_class) || + put_user(kp->which, &up->which) || put_user(kp->count, &up->count) || put_user(kp->error_idx, &up->error_idx) || copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved))) diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 4a1d9fdd1..c9d5537b6 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -1491,6 +1491,17 @@ static int new_to_user(struct v4l2_ext_control *c, return ptr_to_user(c, ctrl, ctrl->p_new); } +/* Helper function: copy the initial control value back to the caller */ +static int def_to_user(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl) +{ + int idx; + + for (idx = 0; idx < ctrl->elems; idx++) + ctrl->type_ops->init(ctrl, idx, ctrl->p_new); + + return ptr_to_user(c, ctrl, ctrl->p_new); +} + /* Helper function: copy the caller-provider value to the given control value */ static int user_to_ptr(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl, @@ -1762,7 +1773,7 @@ static struct v4l2_ctrl_ref *find_private_ref( list_for_each_entry(ref, &hdl->ctrl_refs, node) { /* Search for private user controls that are compatible with VIDIOC_G/S_CTRL. */ - if (V4L2_CTRL_ID2CLASS(ref->ctrl->id) == V4L2_CTRL_CLASS_USER && + if (V4L2_CTRL_ID2WHICH(ref->ctrl->id) == V4L2_CTRL_CLASS_USER && V4L2_CTRL_DRIVER_PRIV(ref->ctrl->id)) { if (!ref->ctrl->is_int) continue; @@ -1831,7 +1842,7 @@ static int handler_new_ref(struct v4l2_ctrl_handler *hdl, struct v4l2_ctrl_ref *ref; struct v4l2_ctrl_ref *new_ref; u32 id = ctrl->id; - u32 class_ctrl = V4L2_CTRL_ID2CLASS(id) | 1; + u32 class_ctrl = V4L2_CTRL_ID2WHICH(id) | 1; int bucket = id % hdl->nr_of_buckets; /* which bucket to use */ /* @@ -2253,9 +2264,9 @@ EXPORT_SYMBOL(v4l2_ctrl_add_handler); bool v4l2_ctrl_radio_filter(const struct v4l2_ctrl *ctrl) { - if (V4L2_CTRL_ID2CLASS(ctrl->id) == V4L2_CTRL_CLASS_FM_TX) + if (V4L2_CTRL_ID2WHICH(ctrl->id) == V4L2_CTRL_CLASS_FM_TX) return true; - if (V4L2_CTRL_ID2CLASS(ctrl->id) == V4L2_CTRL_CLASS_FM_RX) + if (V4L2_CTRL_ID2WHICH(ctrl->id) == V4L2_CTRL_CLASS_FM_RX) return true; switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: @@ -2710,7 +2721,9 @@ static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl, cs->error_idx = i; - if (cs->ctrl_class && V4L2_CTRL_ID2CLASS(id) != cs->ctrl_class) + if (cs->which && + cs->which != V4L2_CTRL_WHICH_DEF_VAL && + V4L2_CTRL_ID2WHICH(id) != cs->which) return -EINVAL; /* Old-style private controls are not allowed for @@ -2787,11 +2800,11 @@ static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl, /* Handles the corner case where cs->count == 0. It checks whether the specified control class exists. If that class ID is 0, then it checks whether there are any controls at all. */ -static int class_check(struct v4l2_ctrl_handler *hdl, u32 ctrl_class) +static int class_check(struct v4l2_ctrl_handler *hdl, u32 which) { - if (ctrl_class == 0) + if (which == 0 || which == V4L2_CTRL_WHICH_DEF_VAL) return list_empty(&hdl->ctrl_refs) ? -EINVAL : 0; - return find_ref_lock(hdl, ctrl_class | 1) ? 0 : -EINVAL; + return find_ref_lock(hdl, which | 1) ? 0 : -EINVAL; } @@ -2803,15 +2816,18 @@ int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs struct v4l2_ctrl_helper *helpers = helper; int ret; int i, j; + bool def_value; + + def_value = (cs->which == V4L2_CTRL_WHICH_DEF_VAL); cs->error_idx = cs->count; - cs->ctrl_class = V4L2_CTRL_ID2CLASS(cs->ctrl_class); + cs->which = V4L2_CTRL_ID2WHICH(cs->which); if (hdl == NULL) return -EINVAL; if (cs->count == 0) - return class_check(hdl, cs->ctrl_class); + return class_check(hdl, cs->which); if (cs->count > ARRAY_SIZE(helper)) { helpers = kmalloc_array(cs->count, sizeof(helper[0]), @@ -2829,9 +2845,11 @@ int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs for (i = 0; !ret && i < cs->count; i++) { int (*ctrl_to_user)(struct v4l2_ext_control *c, - struct v4l2_ctrl *ctrl) = cur_to_user; + struct v4l2_ctrl *ctrl); struct v4l2_ctrl *master; + ctrl_to_user = def_value ? def_to_user : cur_to_user; + if (helpers[i].mref == NULL) continue; @@ -2841,8 +2859,9 @@ int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs v4l2_ctrl_lock(master); /* g_volatile_ctrl will update the new control values */ - if ((master->flags & V4L2_CTRL_FLAG_VOLATILE) || - (master->has_volatiles && !is_cur_manual(master))) { + if (!def_value && + ((master->flags & V4L2_CTRL_FLAG_VOLATILE) || + (master->has_volatiles && !is_cur_manual(master)))) { for (j = 0; j < master->ncontrols; j++) cur_to_new(master->cluster[j]); ret = call_op(master, g_volatile_ctrl); @@ -3064,13 +3083,18 @@ static int try_set_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl, int ret; cs->error_idx = cs->count; - cs->ctrl_class = V4L2_CTRL_ID2CLASS(cs->ctrl_class); + + /* Default value cannot be changed */ + if (cs->which == V4L2_CTRL_WHICH_DEF_VAL) + return -EINVAL; + + cs->which = V4L2_CTRL_ID2WHICH(cs->which); if (hdl == NULL) return -EINVAL; if (cs->count == 0) - return class_check(hdl, cs->ctrl_class); + return class_check(hdl, cs->which); if (cs->count > ARRAY_SIZE(helper)) { helpers = kmalloc_array(cs->count, sizeof(helper[0]), @@ -3300,7 +3324,8 @@ EXPORT_SYMBOL(v4l2_ctrl_notify); int __v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl, s64 min, s64 max, u64 step, s64 def) { - bool changed; + bool value_changed; + bool range_changed = false; int ret; lockdep_assert_held(ctrl->handler->lock); @@ -3324,10 +3349,14 @@ int __v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl, default: return -EINVAL; } - ctrl->minimum = min; - ctrl->maximum = max; - ctrl->step = step; - ctrl->default_value = def; + if ((ctrl->minimum != min) || (ctrl->maximum != max) || + (ctrl->step != step) || ctrl->default_value != def) { + range_changed = true; + ctrl->minimum = min; + ctrl->maximum = max; + ctrl->step = step; + ctrl->default_value = def; + } cur_to_new(ctrl); if (validate_new(ctrl, ctrl->p_new)) { if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64) @@ -3337,12 +3366,12 @@ int __v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl, } if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64) - changed = *ctrl->p_new.p_s64 != *ctrl->p_cur.p_s64; + value_changed = *ctrl->p_new.p_s64 != *ctrl->p_cur.p_s64; else - changed = *ctrl->p_new.p_s32 != *ctrl->p_cur.p_s32; - if (changed) + value_changed = *ctrl->p_new.p_s32 != *ctrl->p_cur.p_s32; + if (value_changed) ret = set_ctrl(NULL, ctrl, V4L2_EVENT_CTRL_CH_RANGE); - else + else if (range_changed) send_event(NULL, ctrl, V4L2_EVENT_CTRL_CH_RANGE); return ret; } diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index 6b1eaeddb..d8e5994cc 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c @@ -194,9 +194,12 @@ static void v4l2_device_release(struct device *cd) mutex_unlock(&videodev_lock); #if defined(CONFIG_MEDIA_CONTROLLER) - if (v4l2_dev->mdev && - vdev->vfl_type != VFL_TYPE_SUBDEV) - media_device_unregister_entity(&vdev->entity); + if (v4l2_dev->mdev) { + /* Remove interfaces and interface links */ + media_devnode_remove(vdev->intf_devnode); + if (vdev->entity.function != MEDIA_ENT_F_UNKNOWN) + media_device_unregister_entity(&vdev->entity); + } #endif /* Do not call v4l2_device_put if there is no release callback set. @@ -723,6 +726,91 @@ static void determine_valid_ioctls(struct video_device *vdev) BASE_VIDIOC_PRIVATE); } +static int video_register_media_controller(struct video_device *vdev, int type) +{ +#if defined(CONFIG_MEDIA_CONTROLLER) + u32 intf_type; + int ret; + + if (!vdev->v4l2_dev->mdev) + return 0; + + vdev->entity.function = MEDIA_ENT_F_UNKNOWN; + + switch (type) { + case VFL_TYPE_GRABBER: + intf_type = MEDIA_INTF_T_V4L_VIDEO; + vdev->entity.function = MEDIA_ENT_F_IO_V4L; + break; + case VFL_TYPE_VBI: + intf_type = MEDIA_INTF_T_V4L_VBI; + vdev->entity.function = MEDIA_ENT_F_IO_VBI; + break; + case VFL_TYPE_SDR: + intf_type = MEDIA_INTF_T_V4L_SWRADIO; + vdev->entity.function = MEDIA_ENT_F_IO_SWRADIO; + break; + case VFL_TYPE_RADIO: + intf_type = MEDIA_INTF_T_V4L_RADIO; + /* + * Radio doesn't have an entity at the V4L2 side to represent + * radio input or output. Instead, the audio input/output goes + * via either physical wires or ALSA. + */ + break; + case VFL_TYPE_SUBDEV: + intf_type = MEDIA_INTF_T_V4L_SUBDEV; + /* Entity will be created via v4l2_device_register_subdev() */ + break; + default: + return 0; + } + + if (vdev->entity.function != MEDIA_ENT_F_UNKNOWN) { + vdev->entity.name = vdev->name; + + /* Needed just for backward compatibility with legacy MC API */ + vdev->entity.info.dev.major = VIDEO_MAJOR; + vdev->entity.info.dev.minor = vdev->minor; + + ret = media_device_register_entity(vdev->v4l2_dev->mdev, + &vdev->entity); + if (ret < 0) { + printk(KERN_WARNING + "%s: media_device_register_entity failed\n", + __func__); + return ret; + } + } + + vdev->intf_devnode = media_devnode_create(vdev->v4l2_dev->mdev, + intf_type, + 0, VIDEO_MAJOR, + vdev->minor); + if (!vdev->intf_devnode) { + media_device_unregister_entity(&vdev->entity); + return -ENOMEM; + } + + if (vdev->entity.function != MEDIA_ENT_F_UNKNOWN) { + struct media_link *link; + + link = media_create_intf_link(&vdev->entity, + &vdev->intf_devnode->intf, + MEDIA_LNK_FL_ENABLED); + if (!link) { + media_devnode_remove(vdev->intf_devnode); + media_device_unregister_entity(&vdev->entity); + return -ENOMEM; + } + } + + /* FIXME: how to create the other interface links? */ + +#endif + return 0; +} + /** * __video_register_device - register video4linux devices * @vdev: video device structure we want to register @@ -918,22 +1006,9 @@ int __video_register_device(struct video_device *vdev, int type, int nr, /* Increase v4l2_device refcount */ v4l2_device_get(vdev->v4l2_dev); -#if defined(CONFIG_MEDIA_CONTROLLER) /* Part 5: Register the entity. */ - if (vdev->v4l2_dev->mdev && - vdev->vfl_type != VFL_TYPE_SUBDEV) { - vdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L; - vdev->entity.name = vdev->name; - vdev->entity.info.dev.major = VIDEO_MAJOR; - vdev->entity.info.dev.minor = vdev->minor; - ret = media_device_register_entity(vdev->v4l2_dev->mdev, - &vdev->entity); - if (ret < 0) - printk(KERN_WARNING - "%s: media_device_register_entity failed\n", - __func__); - } -#endif + ret = video_register_media_controller(vdev, type); + /* Part 6: Activate this minor. The char device can now be used. */ set_bit(V4L2_FL_REGISTERED, &vdev->flags); diff --git a/drivers/media/v4l2-core/v4l2-device.c b/drivers/media/v4l2-core/v4l2-device.c index 5b0a30b92..06fa5f1b2 100644 --- a/drivers/media/v4l2-core/v4l2-device.c +++ b/drivers/media/v4l2-core/v4l2-device.c @@ -118,11 +118,20 @@ void v4l2_device_unregister(struct v4l2_device *v4l2_dev) if (sd->flags & V4L2_SUBDEV_FL_IS_I2C) { struct i2c_client *client = v4l2_get_subdevdata(sd); - /* We need to unregister the i2c client explicitly. - We cannot rely on i2c_del_adapter to always - unregister clients for us, since if the i2c bus - is a platform bus, then it is never deleted. */ - if (client) + /* + * We need to unregister the i2c client + * explicitly. We cannot rely on + * i2c_del_adapter to always unregister + * clients for us, since if the i2c bus is a + * platform bus, then it is never deleted. + * + * Device tree or ACPI based devices must not + * be unregistered as they have not been + * registered by us, and would not be + * re-created by just probing the V4L2 driver. + */ + if (client && + !client->dev.of_node && !client->dev.fwnode) i2c_unregister_device(client); continue; } @@ -131,7 +140,7 @@ void v4l2_device_unregister(struct v4l2_device *v4l2_dev) if (sd->flags & V4L2_SUBDEV_FL_IS_SPI) { struct spi_device *spi = v4l2_get_subdevdata(sd); - if (spi) + if (spi && !spi->dev.of_node && !spi->dev.fwnode) spi_unregister_device(spi); continue; } @@ -171,26 +180,26 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev, return -ENODEV; sd->v4l2_dev = v4l2_dev; - if (sd->internal_ops && sd->internal_ops->registered) { - err = sd->internal_ops->registered(sd); - if (err) - goto error_module; - } - /* This just returns 0 if either of the two args is NULL */ err = v4l2_ctrl_add_handler(v4l2_dev->ctrl_handler, sd->ctrl_handler, NULL); if (err) - goto error_unregister; + goto error_module; #if defined(CONFIG_MEDIA_CONTROLLER) /* Register the entity. */ if (v4l2_dev->mdev) { err = media_device_register_entity(v4l2_dev->mdev, entity); if (err < 0) - goto error_unregister; + goto error_module; } #endif + if (sd->internal_ops && sd->internal_ops->registered) { + err = sd->internal_ops->registered(sd); + if (err) + goto error_unregister; + } + spin_lock(&v4l2_dev->lock); list_add_tail(&sd->list, &v4l2_dev->subdevs); spin_unlock(&v4l2_dev->lock); @@ -198,8 +207,9 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev, return 0; error_unregister: - if (sd->internal_ops && sd->internal_ops->unregistered) - sd->internal_ops->unregistered(sd); +#if defined(CONFIG_MEDIA_CONTROLLER) + media_device_unregister_entity(entity); +#endif error_module: if (!sd->owner_v4l2_dev) module_put(sd->owner); @@ -249,6 +259,19 @@ int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev) #if defined(CONFIG_MEDIA_CONTROLLER) sd->entity.info.dev.major = VIDEO_MAJOR; sd->entity.info.dev.minor = vdev->minor; + + /* Interface is created by __video_register_device() */ + if (vdev->v4l2_dev->mdev) { + struct media_link *link; + + link = media_create_intf_link(&sd->entity, + &vdev->intf_devnode->intf, + MEDIA_LNK_FL_ENABLED); + if (!link) { + err = -ENOMEM; + goto clean_up; + } + } #endif sd->devnode = vdev; } @@ -285,7 +308,10 @@ void v4l2_device_unregister_subdev(struct v4l2_subdev *sd) #if defined(CONFIG_MEDIA_CONTROLLER) if (v4l2_dev->mdev) { - media_entity_remove_links(&sd->entity); + /* + * No need to explicitly remove links, as both pads and + * links are removed by the function below, in the right order + */ media_device_unregister_entity(&sd->entity); } #endif diff --git a/drivers/media/v4l2-core/v4l2-dv-timings.c b/drivers/media/v4l2-core/v4l2-dv-timings.c index 6a83d6191..ec258b730 100644 --- a/drivers/media/v4l2-core/v4l2-dv-timings.c +++ b/drivers/media/v4l2-core/v4l2-dv-timings.c @@ -209,8 +209,13 @@ bool v4l2_find_dv_timings_cap(struct v4l2_dv_timings *t, if (v4l2_valid_dv_timings(v4l2_dv_timings_presets + i, cap, fnc, fnc_handle) && v4l2_match_dv_timings(t, v4l2_dv_timings_presets + i, - pclock_delta)) { + pclock_delta, false)) { + u32 flags = t->bt.flags & V4L2_DV_FL_REDUCED_FPS; + *t = v4l2_dv_timings_presets[i]; + if (can_reduce_fps(&t->bt)) + t->bt.flags |= flags; + return true; } } @@ -223,12 +228,14 @@ EXPORT_SYMBOL_GPL(v4l2_find_dv_timings_cap); * @t1 - compare this v4l2_dv_timings struct... * @t2 - with this struct. * @pclock_delta - the allowed pixelclock deviation. + * @match_reduced_fps - if true, then fail if V4L2_DV_FL_REDUCED_FPS does not + * match. * * Compare t1 with t2 with a given margin of error for the pixelclock. */ bool v4l2_match_dv_timings(const struct v4l2_dv_timings *t1, const struct v4l2_dv_timings *t2, - unsigned pclock_delta) + unsigned pclock_delta, bool match_reduced_fps) { if (t1->type != t2->type || t1->type != V4L2_DV_BT_656_1120) return false; @@ -239,9 +246,14 @@ bool v4l2_match_dv_timings(const struct v4l2_dv_timings *t1, t1->bt.pixelclock >= t2->bt.pixelclock - pclock_delta && t1->bt.pixelclock <= t2->bt.pixelclock + pclock_delta && t1->bt.hfrontporch == t2->bt.hfrontporch && + t1->bt.hsync == t2->bt.hsync && + t1->bt.hbackporch == t2->bt.hbackporch && t1->bt.vfrontporch == t2->bt.vfrontporch && t1->bt.vsync == t2->bt.vsync && t1->bt.vbackporch == t2->bt.vbackporch && + (!match_reduced_fps || + (t1->bt.flags & V4L2_DV_FL_REDUCED_FPS) == + (t2->bt.flags & V4L2_DV_FL_REDUCED_FPS)) && (!t1->bt.interlaced || (t1->bt.il_vfrontporch == t2->bt.il_vfrontporch && t1->bt.il_vsync == t2->bt.il_vsync && diff --git a/drivers/media/v4l2-core/v4l2-flash-led-class.c b/drivers/media/v4l2-core/v4l2-flash-led-class.c index 5bdfb8d52..fc5ff8b21 100644 --- a/drivers/media/v4l2-core/v4l2-flash-led-class.c +++ b/drivers/media/v4l2-core/v4l2-flash-led-class.c @@ -107,10 +107,10 @@ static void v4l2_flash_set_led_brightness(struct v4l2_flash *v4l2_flash, if (ctrls[LED_MODE]->val != V4L2_FLASH_LED_MODE_TORCH) return; - led_set_brightness(&v4l2_flash->fled_cdev->led_cdev, + led_set_brightness_sync(&v4l2_flash->fled_cdev->led_cdev, brightness); } else { - led_set_brightness(&v4l2_flash->iled_cdev->led_cdev, + led_set_brightness_sync(&v4l2_flash->iled_cdev->led_cdev, brightness); } } @@ -206,11 +206,11 @@ static int v4l2_flash_s_ctrl(struct v4l2_ctrl *c) case V4L2_CID_FLASH_LED_MODE: switch (c->val) { case V4L2_FLASH_LED_MODE_NONE: - led_set_brightness(led_cdev, LED_OFF); + led_set_brightness_sync(led_cdev, LED_OFF); return led_set_flash_strobe(fled_cdev, false); case V4L2_FLASH_LED_MODE_FLASH: /* Turn the torch LED off */ - led_set_brightness(led_cdev, LED_OFF); + led_set_brightness_sync(led_cdev, LED_OFF); if (ctrls[STROBE_SOURCE]) { external_strobe = (ctrls[STROBE_SOURCE]->val == V4L2_FLASH_STROBE_SOURCE_EXTERNAL); @@ -651,11 +651,11 @@ struct v4l2_flash *v4l2_flash_init( sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; strlcpy(sd->name, config->dev_name, sizeof(sd->name)); - ret = media_entity_init(&sd->entity, 0, NULL, 0); + ret = media_entity_pads_init(&sd->entity, 0, NULL); if (ret < 0) return ERR_PTR(ret); - sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_FLASH; + sd->entity.function = MEDIA_ENT_F_FLASH; ret = v4l2_flash_init_controls(v4l2_flash, config); if (ret < 0) diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 7486af2c8..8a018c6dd 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -565,8 +565,8 @@ static void v4l_print_ext_controls(const void *arg, bool write_only) const struct v4l2_ext_controls *p = arg; int i; - pr_cont("class=0x%x, count=%d, error_idx=%d", - p->ctrl_class, p->count, p->error_idx); + pr_cont("which=0x%x, count=%d, error_idx=%d", + p->which, p->count, p->error_idx); for (i = 0; i < p->count; i++) { if (!p->controls[i].size) pr_cont(", id/val=0x%x/0x%x", @@ -902,13 +902,13 @@ static int check_ext_ctrls(struct v4l2_ext_controls *c, int allow_priv) Only when passed in through VIDIOC_G_CTRL and VIDIOC_S_CTRL is it allowed for backwards compatibility. */ - if (!allow_priv && c->ctrl_class == V4L2_CID_PRIVATE_BASE) + if (!allow_priv && c->which == V4L2_CID_PRIVATE_BASE) return 0; - if (c->ctrl_class == 0) + if (!c->which) return 1; /* Check that all controls are from the same control class. */ for (i = 0; i < c->count; i++) { - if (V4L2_CTRL_ID2CLASS(c->controls[i].id) != c->ctrl_class) { + if (V4L2_CTRL_ID2WHICH(c->controls[i].id) != c->which) { c->error_idx = i; return 0; } @@ -1969,7 +1969,7 @@ static int v4l_g_ctrl(const struct v4l2_ioctl_ops *ops, if (ops->vidioc_g_ext_ctrls == NULL) return -ENOTTY; - ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(p->id); + ctrls.which = V4L2_CTRL_ID2WHICH(p->id); ctrls.count = 1; ctrls.controls = &ctrl; ctrl.id = p->id; @@ -2003,7 +2003,7 @@ static int v4l_s_ctrl(const struct v4l2_ioctl_ops *ops, if (ops->vidioc_s_ext_ctrls == NULL) return -ENOTTY; - ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(p->id); + ctrls.which = V4L2_CTRL_ID2WHICH(p->id); ctrls.count = 1; ctrls.controls = &ctrl; ctrl.id = p->id; diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index 83615b8fb..d63083803 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -526,7 +526,7 @@ static int v4l2_subdev_link_validate_get_format(struct media_pad *pad, struct v4l2_subdev_format *fmt) { - if (media_entity_type(pad->entity) == MEDIA_ENT_T_V4L2_SUBDEV) { + if (is_media_entity_v4l2_subdev(pad->entity)) { struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(pad->entity); @@ -535,9 +535,9 @@ v4l2_subdev_link_validate_get_format(struct media_pad *pad, return v4l2_subdev_call(sd, pad, get_fmt, NULL, fmt); } - WARN(pad->entity->type != MEDIA_ENT_T_DEVNODE_V4L, + WARN(pad->entity->function != MEDIA_ENT_F_IO_V4L, "Driver bug! Wrong media entity type 0x%08x, entity %s\n", - pad->entity->type, pad->entity->name); + pad->entity->function, pad->entity->name); return -EINVAL; } @@ -584,7 +584,7 @@ void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops) sd->host_priv = NULL; #if defined(CONFIG_MEDIA_CONTROLLER) sd->entity.name = sd->name; - sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV; + sd->entity.function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN; #endif } EXPORT_SYMBOL(v4l2_subdev_init); diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 33bdd8106..ff8953ae5 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -28,11 +28,161 @@ #include <trace/events/vb2.h> -#include "videobuf2-internal.h" +static int debug; +module_param(debug, int, 0644); -int vb2_debug; -EXPORT_SYMBOL_GPL(vb2_debug); -module_param_named(debug, vb2_debug, int, 0644); +#define dprintk(level, fmt, arg...) \ + do { \ + if (debug >= level) \ + pr_info("vb2-core: %s: " fmt, __func__, ## arg); \ + } while (0) + +#ifdef CONFIG_VIDEO_ADV_DEBUG + +/* + * If advanced debugging is on, then count how often each op is called + * successfully, which can either be per-buffer or per-queue. + * + * This makes it easy to check that the 'init' and 'cleanup' + * (and variations thereof) stay balanced. + */ + +#define log_memop(vb, op) \ + dprintk(2, "call_memop(%p, %d, %s)%s\n", \ + (vb)->vb2_queue, (vb)->index, #op, \ + (vb)->vb2_queue->mem_ops->op ? "" : " (nop)") + +#define call_memop(vb, op, args...) \ +({ \ + struct vb2_queue *_q = (vb)->vb2_queue; \ + int err; \ + \ + log_memop(vb, op); \ + err = _q->mem_ops->op ? _q->mem_ops->op(args) : 0; \ + if (!err) \ + (vb)->cnt_mem_ ## op++; \ + err; \ +}) + +#define call_ptr_memop(vb, op, args...) \ +({ \ + struct vb2_queue *_q = (vb)->vb2_queue; \ + void *ptr; \ + \ + log_memop(vb, op); \ + ptr = _q->mem_ops->op ? _q->mem_ops->op(args) : NULL; \ + if (!IS_ERR_OR_NULL(ptr)) \ + (vb)->cnt_mem_ ## op++; \ + ptr; \ +}) + +#define call_void_memop(vb, op, args...) \ +({ \ + struct vb2_queue *_q = (vb)->vb2_queue; \ + \ + log_memop(vb, op); \ + if (_q->mem_ops->op) \ + _q->mem_ops->op(args); \ + (vb)->cnt_mem_ ## op++; \ +}) + +#define log_qop(q, op) \ + dprintk(2, "call_qop(%p, %s)%s\n", q, #op, \ + (q)->ops->op ? "" : " (nop)") + +#define call_qop(q, op, args...) \ +({ \ + int err; \ + \ + log_qop(q, op); \ + err = (q)->ops->op ? (q)->ops->op(args) : 0; \ + if (!err) \ + (q)->cnt_ ## op++; \ + err; \ +}) + +#define call_void_qop(q, op, args...) \ +({ \ + log_qop(q, op); \ + if ((q)->ops->op) \ + (q)->ops->op(args); \ + (q)->cnt_ ## op++; \ +}) + +#define log_vb_qop(vb, op, args...) \ + dprintk(2, "call_vb_qop(%p, %d, %s)%s\n", \ + (vb)->vb2_queue, (vb)->index, #op, \ + (vb)->vb2_queue->ops->op ? "" : " (nop)") + +#define call_vb_qop(vb, op, args...) \ +({ \ + int err; \ + \ + log_vb_qop(vb, op); \ + err = (vb)->vb2_queue->ops->op ? \ + (vb)->vb2_queue->ops->op(args) : 0; \ + if (!err) \ + (vb)->cnt_ ## op++; \ + err; \ +}) + +#define call_void_vb_qop(vb, op, args...) \ +({ \ + log_vb_qop(vb, op); \ + if ((vb)->vb2_queue->ops->op) \ + (vb)->vb2_queue->ops->op(args); \ + (vb)->cnt_ ## op++; \ +}) + +#else + +#define call_memop(vb, op, args...) \ + ((vb)->vb2_queue->mem_ops->op ? \ + (vb)->vb2_queue->mem_ops->op(args) : 0) + +#define call_ptr_memop(vb, op, args...) \ + ((vb)->vb2_queue->mem_ops->op ? \ + (vb)->vb2_queue->mem_ops->op(args) : NULL) + +#define call_void_memop(vb, op, args...) \ + do { \ + if ((vb)->vb2_queue->mem_ops->op) \ + (vb)->vb2_queue->mem_ops->op(args); \ + } while (0) + +#define call_qop(q, op, args...) \ + ((q)->ops->op ? (q)->ops->op(args) : 0) + +#define call_void_qop(q, op, args...) \ + do { \ + if ((q)->ops->op) \ + (q)->ops->op(args); \ + } while (0) + +#define call_vb_qop(vb, op, args...) \ + ((vb)->vb2_queue->ops->op ? (vb)->vb2_queue->ops->op(args) : 0) + +#define call_void_vb_qop(vb, op, args...) \ + do { \ + if ((vb)->vb2_queue->ops->op) \ + (vb)->vb2_queue->ops->op(args); \ + } while (0) + +#endif + +#define call_bufop(q, op, args...) \ +({ \ + int ret = 0; \ + if (q && q->buf_ops && q->buf_ops->op) \ + ret = q->buf_ops->op(args); \ + ret; \ +}) + +#define call_void_bufop(q, op, args...) \ +({ \ + if (q && q->buf_ops && q->buf_ops->op) \ + q->buf_ops->op(args); \ +}) static void __vb2_queue_cancel(struct vb2_queue *q); static void __enqueue_in_driver(struct vb2_buffer *vb); @@ -53,7 +203,7 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb) * NOTE: mmapped areas should be page aligned */ for (plane = 0; plane < vb->num_planes; ++plane) { - unsigned long size = PAGE_ALIGN(q->plane_sizes[plane]); + unsigned long size = PAGE_ALIGN(vb->planes[plane].length); mem_priv = call_ptr_memop(vb, alloc, q->alloc_ctx[plane], size, dma_dir, q->gfp_flags); @@ -62,7 +212,6 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb) /* Associate allocator private data with this plane */ vb->planes[plane].mem_priv = mem_priv; - vb->planes[plane].length = q->plane_sizes[plane]; } return 0; @@ -137,57 +286,30 @@ static void __vb2_buf_dmabuf_put(struct vb2_buffer *vb) } /** - * __setup_lengths() - setup initial lengths for every plane in - * every buffer on the queue - */ -static void __setup_lengths(struct vb2_queue *q, unsigned int n) -{ - unsigned int buffer, plane; - struct vb2_buffer *vb; - - for (buffer = q->num_buffers; buffer < q->num_buffers + n; ++buffer) { - vb = q->bufs[buffer]; - if (!vb) - continue; - - for (plane = 0; plane < vb->num_planes; ++plane) - vb->planes[plane].length = q->plane_sizes[plane]; - } -} - -/** * __setup_offsets() - setup unique offsets ("cookies") for every plane in - * every buffer on the queue + * the buffer. */ -static void __setup_offsets(struct vb2_queue *q, unsigned int n) +static void __setup_offsets(struct vb2_buffer *vb) { - unsigned int buffer, plane; - struct vb2_buffer *vb; - unsigned long off; + struct vb2_queue *q = vb->vb2_queue; + unsigned int plane; + unsigned long off = 0; + + if (vb->index) { + struct vb2_buffer *prev = q->bufs[vb->index - 1]; + struct vb2_plane *p = &prev->planes[prev->num_planes - 1]; - if (q->num_buffers) { - struct vb2_plane *p; - vb = q->bufs[q->num_buffers - 1]; - p = &vb->planes[vb->num_planes - 1]; off = PAGE_ALIGN(p->m.offset + p->length); - } else { - off = 0; } - for (buffer = q->num_buffers; buffer < q->num_buffers + n; ++buffer) { - vb = q->bufs[buffer]; - if (!vb) - continue; - - for (plane = 0; plane < vb->num_planes; ++plane) { - vb->planes[plane].m.offset = off; + for (plane = 0; plane < vb->num_planes; ++plane) { + vb->planes[plane].m.offset = off; - dprintk(3, "buffer %d, plane %d offset 0x%08lx\n", - buffer, plane, off); + dprintk(3, "buffer %d, plane %d offset 0x%08lx\n", + vb->index, plane, off); - off += vb->planes[plane].length; - off = PAGE_ALIGN(off); - } + off += vb->planes[plane].length; + off = PAGE_ALIGN(off); } } @@ -199,9 +321,10 @@ static void __setup_offsets(struct vb2_queue *q, unsigned int n) * Returns the number of buffers successfully allocated. */ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory, - unsigned int num_buffers, unsigned int num_planes) + unsigned int num_buffers, unsigned int num_planes, + const unsigned plane_sizes[VB2_MAX_PLANES]) { - unsigned int buffer; + unsigned int buffer, plane; struct vb2_buffer *vb; int ret; @@ -219,6 +342,11 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory, vb->index = q->num_buffers + buffer; vb->type = q->type; vb->memory = memory; + for (plane = 0; plane < num_planes; ++plane) { + vb->planes[plane].length = plane_sizes[plane]; + vb->planes[plane].min_length = plane_sizes[plane]; + } + q->bufs[vb->index] = vb; /* Allocate video buffer memory for the MMAP type */ if (memory == VB2_MEMORY_MMAP) { @@ -226,9 +354,11 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory, if (ret) { dprintk(1, "failed allocating memory for " "buffer %d\n", buffer); + q->bufs[vb->index] = NULL; kfree(vb); break; } + __setup_offsets(vb); /* * Call the driver-provided buffer initialization * callback, if given. An error in initialization @@ -239,18 +369,13 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory, dprintk(1, "buffer %d %p initialization" " failed\n", buffer, vb); __vb2_buf_mem_free(vb); + q->bufs[vb->index] = NULL; kfree(vb); break; } } - - q->bufs[q->num_buffers + buffer] = vb; } - __setup_lengths(q, buffer); - if (memory == VB2_MEMORY_MMAP) - __setup_offsets(q, buffer); - dprintk(1, "allocated %d buffers, %d plane(s) each\n", buffer, num_planes); @@ -330,7 +455,7 @@ static int __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) bool unbalanced = q->cnt_start_streaming != q->cnt_stop_streaming || q->cnt_wait_prepare != q->cnt_wait_finish; - if (unbalanced || vb2_debug) { + if (unbalanced || debug) { pr_info("vb2: counters for queue %p:%s\n", q, unbalanced ? " UNBALANCED!" : ""); pr_info("vb2: setup: %u start_streaming: %u stop_streaming: %u\n", @@ -356,7 +481,7 @@ static int __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) vb->cnt_buf_prepare != vb->cnt_buf_finish || vb->cnt_buf_init != vb->cnt_buf_cleanup; - if (unbalanced || vb2_debug) { + if (unbalanced || debug) { pr_info("vb2: counters for queue %p, buffer %d:%s\n", q, buffer, unbalanced ? " UNBALANCED!" : ""); pr_info("vb2: buf_init: %u buf_cleanup: %u buf_prepare: %u buf_finish: %u\n", @@ -442,13 +567,10 @@ static bool __buffers_in_use(struct vb2_queue *q) * Should be called from vidioc_querybuf ioctl handler in driver. * The passed buffer should have been verified. * This function fills the relevant information for the userspace. - * - * The return values from this function are intended to be directly returned - * from vidioc_querybuf handler in driver. */ -int vb2_core_querybuf(struct vb2_queue *q, unsigned int index, void *pb) +void vb2_core_querybuf(struct vb2_queue *q, unsigned int index, void *pb) { - return call_bufop(q, fill_user_buffer, q->bufs[index], pb); + call_void_bufop(q, fill_user_buffer, q->bufs[index], pb); } EXPORT_SYMBOL_GPL(vb2_core_querybuf); @@ -570,6 +692,7 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, unsigned int *count) { unsigned int num_buffers, allocated_buffers, num_planes = 0; + unsigned plane_sizes[VB2_MAX_PLANES] = { }; int ret; if (q->streaming) { @@ -613,7 +736,6 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, */ num_buffers = min_t(unsigned int, *count, VB2_MAX_FRAME); num_buffers = max_t(unsigned int, num_buffers, q->min_buffers_needed); - memset(q->plane_sizes, 0, sizeof(q->plane_sizes)); memset(q->alloc_ctx, 0, sizeof(q->alloc_ctx)); q->memory = memory; @@ -621,14 +743,14 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, * Ask the driver how many buffers and planes per buffer it requires. * Driver also sets the size and allocator context for each plane. */ - ret = call_qop(q, queue_setup, q, NULL, &num_buffers, &num_planes, - q->plane_sizes, q->alloc_ctx); + ret = call_qop(q, queue_setup, q, &num_buffers, &num_planes, + plane_sizes, q->alloc_ctx); if (ret) return ret; /* Finally, allocate buffers and video memory */ allocated_buffers = - __vb2_queue_alloc(q, memory, num_buffers, num_planes); + __vb2_queue_alloc(q, memory, num_buffers, num_planes, plane_sizes); if (allocated_buffers == 0) { dprintk(1, "memory allocation failed\n"); return -ENOMEM; @@ -646,9 +768,16 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, */ if (!ret && allocated_buffers < num_buffers) { num_buffers = allocated_buffers; + /* + * num_planes is set by the previous queue_setup(), but since it + * signals to queue_setup() whether it is called from create_bufs() + * vs reqbufs() we zero it here to signal that queue_setup() is + * called for the reqbufs() case. + */ + num_planes = 0; - ret = call_qop(q, queue_setup, q, NULL, &num_buffers, - &num_planes, q->plane_sizes, q->alloc_ctx); + ret = call_qop(q, queue_setup, q, &num_buffers, + &num_planes, plane_sizes, q->alloc_ctx); if (!ret && allocated_buffers < num_buffers) ret = -ENOMEM; @@ -701,9 +830,11 @@ EXPORT_SYMBOL_GPL(vb2_core_reqbufs); * from vidioc_create_bufs handler in driver. */ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, - unsigned int *count, const void *parg) + unsigned int *count, unsigned requested_planes, + const unsigned requested_sizes[]) { unsigned int num_planes = 0, num_buffers, allocated_buffers; + unsigned plane_sizes[VB2_MAX_PLANES] = { }; int ret; if (q->num_buffers == VB2_MAX_FRAME) { @@ -712,7 +843,6 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, } if (!q->num_buffers) { - memset(q->plane_sizes, 0, sizeof(q->plane_sizes)); memset(q->alloc_ctx, 0, sizeof(q->alloc_ctx)); q->memory = memory; q->waiting_for_buffers = !q->is_output; @@ -720,18 +850,23 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, num_buffers = min(*count, VB2_MAX_FRAME - q->num_buffers); + if (requested_planes && requested_sizes) { + num_planes = requested_planes; + memcpy(plane_sizes, requested_sizes, sizeof(plane_sizes)); + } + /* * Ask the driver, whether the requested number of buffers, planes per * buffer and their sizes are acceptable */ - ret = call_qop(q, queue_setup, q, parg, &num_buffers, - &num_planes, q->plane_sizes, q->alloc_ctx); + ret = call_qop(q, queue_setup, q, &num_buffers, + &num_planes, plane_sizes, q->alloc_ctx); if (ret) return ret; /* Finally, allocate buffers and video memory */ allocated_buffers = __vb2_queue_alloc(q, memory, num_buffers, - num_planes); + num_planes, plane_sizes); if (allocated_buffers == 0) { dprintk(1, "memory allocation failed\n"); return -ENOMEM; @@ -747,8 +882,8 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, * q->num_buffers contains the total number of buffers, that the * queue driver has set up */ - ret = call_qop(q, queue_setup, q, parg, &num_buffers, - &num_planes, q->plane_sizes, q->alloc_ctx); + ret = call_qop(q, queue_setup, q, &num_buffers, + &num_planes, plane_sizes, q->alloc_ctx); if (!ret && allocated_buffers < num_buffers) ret = -ENOMEM; @@ -928,8 +1063,11 @@ EXPORT_SYMBOL_GPL(vb2_discard_done); */ static int __qbuf_mmap(struct vb2_buffer *vb, const void *pb) { - int ret = call_bufop(vb->vb2_queue, fill_vb2_buffer, - vb, pb, vb->planes); + int ret = 0; + + if (pb) + ret = call_bufop(vb->vb2_queue, fill_vb2_buffer, + vb, pb, vb->planes); return ret ? ret : call_vb_qop(vb, buf_prepare, vb); } @@ -942,14 +1080,16 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const void *pb) struct vb2_queue *q = vb->vb2_queue; void *mem_priv; unsigned int plane; - int ret; + int ret = 0; enum dma_data_direction dma_dir = q->is_output ? DMA_TO_DEVICE : DMA_FROM_DEVICE; bool reacquired = vb->planes[0].mem_priv == NULL; memset(planes, 0, sizeof(planes[0]) * vb->num_planes); /* Copy relevant information provided by the userspace */ - ret = call_bufop(vb->vb2_queue, fill_vb2_buffer, vb, pb, planes); + if (pb) + ret = call_bufop(vb->vb2_queue, fill_vb2_buffer, + vb, pb, planes); if (ret) return ret; @@ -964,11 +1104,12 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const void *pb) "reacquiring memory\n", plane); /* Check if the provided plane buffer is large enough */ - if (planes[plane].length < q->plane_sizes[plane]) { + if (planes[plane].length < vb->planes[plane].min_length) { dprintk(1, "provided buffer size %u is less than " "setup size %u for plane %d\n", planes[plane].length, - q->plane_sizes[plane], plane); + vb->planes[plane].min_length, + plane); ret = -EINVAL; goto err; } @@ -1056,14 +1197,16 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const void *pb) struct vb2_queue *q = vb->vb2_queue; void *mem_priv; unsigned int plane; - int ret; + int ret = 0; enum dma_data_direction dma_dir = q->is_output ? DMA_TO_DEVICE : DMA_FROM_DEVICE; bool reacquired = vb->planes[0].mem_priv == NULL; memset(planes, 0, sizeof(planes[0]) * vb->num_planes); /* Copy relevant information provided by the userspace */ - ret = call_bufop(vb->vb2_queue, fill_vb2_buffer, vb, pb, planes); + if (pb) + ret = call_bufop(vb->vb2_queue, fill_vb2_buffer, + vb, pb, planes); if (ret) return ret; @@ -1081,7 +1224,7 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const void *pb) if (planes[plane].length == 0) planes[plane].length = dbuf->size; - if (planes[plane].length < q->plane_sizes[plane]) { + if (planes[plane].length < vb->planes[plane].min_length) { dprintk(1, "invalid dmabuf length for plane %d\n", plane); ret = -EINVAL; @@ -1263,9 +1406,7 @@ int vb2_core_prepare_buf(struct vb2_queue *q, unsigned int index, void *pb) return ret; /* Fill buffer information for the userspace */ - ret = call_bufop(q, fill_user_buffer, vb, pb); - if (ret) - return ret; + call_void_bufop(q, fill_user_buffer, vb, pb); dprintk(1, "prepare of buffer %d succeeded\n", vb->index); @@ -1386,7 +1527,8 @@ int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb) q->waiting_for_buffers = false; vb->state = VB2_BUF_STATE_QUEUED; - call_bufop(q, set_timestamp, vb, pb); + if (pb) + call_void_bufop(q, copy_timestamp, vb, pb); trace_vb2_qbuf(q, vb); @@ -1398,9 +1540,8 @@ int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb) __enqueue_in_driver(vb); /* Fill buffer information for the userspace */ - ret = call_bufop(q, fill_user_buffer, vb, pb); - if (ret) - return ret; + if (pb) + call_void_bufop(q, fill_user_buffer, vb, pb); /* * If streamon has been called, and we haven't yet called @@ -1599,7 +1740,8 @@ static void __vb2_dqbuf(struct vb2_buffer *vb) * The return values from this function are intended to be directly returned * from vidioc_dqbuf handler in driver. */ -int vb2_core_dqbuf(struct vb2_queue *q, void *pb, bool nonblocking) +int vb2_core_dqbuf(struct vb2_queue *q, unsigned int *pindex, void *pb, + bool nonblocking) { struct vb2_buffer *vb = NULL; int ret; @@ -1622,10 +1764,12 @@ int vb2_core_dqbuf(struct vb2_queue *q, void *pb, bool nonblocking) call_void_vb_qop(vb, buf_finish, vb); + if (pindex) + *pindex = vb->index; + /* Fill buffer information for the userspace */ - ret = call_bufop(q, fill_user_buffer, vb, pb); - if (ret) - return ret; + if (pb) + call_void_bufop(q, fill_user_buffer, vb, pb); /* Remove from videobuf queue */ list_del(&vb->queued_entry); @@ -1698,7 +1842,7 @@ static void __vb2_queue_cancel(struct vb2_queue *q) * that's done in dqbuf, but that's not going to happen when we * cancel the whole queue. Note: this code belongs here, not in * __vb2_dqbuf() since in vb2_internal_dqbuf() there is a critical - * call to __fill_v4l2_buffer() after buf_finish(). That order can't + * call to __fill_user_buffer() after buf_finish(). That order can't * be changed, so we can't move the buf_finish() to __vb2_dqbuf(). */ for (i = 0; i < q->num_buffers; ++i) { @@ -2073,6 +2217,8 @@ int vb2_core_queue_init(struct vb2_queue *q) } EXPORT_SYMBOL_GPL(vb2_core_queue_init); +static int __vb2_init_fileio(struct vb2_queue *q, int read); +static int __vb2_cleanup_fileio(struct vb2_queue *q); /** * vb2_core_queue_release() - stop streaming, release the queue and free memory * @q: videobuf2 queue @@ -2083,6 +2229,7 @@ EXPORT_SYMBOL_GPL(vb2_core_queue_init); */ void vb2_core_queue_release(struct vb2_queue *q) { + __vb2_cleanup_fileio(q); __vb2_queue_cancel(q); mutex_lock(&q->mmap_lock); __vb2_queue_free(q, q->num_buffers); @@ -2090,6 +2237,596 @@ void vb2_core_queue_release(struct vb2_queue *q) } EXPORT_SYMBOL_GPL(vb2_core_queue_release); -MODULE_DESCRIPTION("Driver helper framework for Video for Linux 2"); +/** + * vb2_core_poll() - implements poll userspace operation + * @q: videobuf2 queue + * @file: file argument passed to the poll file operation handler + * @wait: wait argument passed to the poll file operation handler + * + * This function implements poll file operation handler for a driver. + * For CAPTURE queues, if a buffer is ready to be dequeued, the userspace will + * be informed that the file descriptor of a video device is available for + * reading. + * For OUTPUT queues, if a buffer is ready to be dequeued, the file descriptor + * will be reported as available for writing. + * + * The return values from this function are intended to be directly returned + * from poll handler in driver. + */ +unsigned int vb2_core_poll(struct vb2_queue *q, struct file *file, + poll_table *wait) +{ + unsigned long req_events = poll_requested_events(wait); + struct vb2_buffer *vb = NULL; + unsigned long flags; + + if (!q->is_output && !(req_events & (POLLIN | POLLRDNORM))) + return 0; + if (q->is_output && !(req_events & (POLLOUT | POLLWRNORM))) + return 0; + + /* + * Start file I/O emulator only if streaming API has not been used yet. + */ + if (q->num_buffers == 0 && !vb2_fileio_is_active(q)) { + if (!q->is_output && (q->io_modes & VB2_READ) && + (req_events & (POLLIN | POLLRDNORM))) { + if (__vb2_init_fileio(q, 1)) + return POLLERR; + } + if (q->is_output && (q->io_modes & VB2_WRITE) && + (req_events & (POLLOUT | POLLWRNORM))) { + if (__vb2_init_fileio(q, 0)) + return POLLERR; + /* + * Write to OUTPUT queue can be done immediately. + */ + return POLLOUT | POLLWRNORM; + } + } + + /* + * There is nothing to wait for if the queue isn't streaming, or if the + * error flag is set. + */ + if (!vb2_is_streaming(q) || q->error) + return POLLERR; + + /* + * For output streams you can call write() as long as there are fewer + * buffers queued than there are buffers available. + */ + if (q->is_output && q->fileio && q->queued_count < q->num_buffers) + return POLLOUT | POLLWRNORM; + + if (list_empty(&q->done_list)) { + /* + * If the last buffer was dequeued from a capture queue, + * return immediately. DQBUF will return -EPIPE. + */ + if (q->last_buffer_dequeued) + return POLLIN | POLLRDNORM; + + poll_wait(file, &q->done_wq, wait); + } + + /* + * Take first buffer available for dequeuing. + */ + spin_lock_irqsave(&q->done_lock, flags); + if (!list_empty(&q->done_list)) + vb = list_first_entry(&q->done_list, struct vb2_buffer, + done_entry); + spin_unlock_irqrestore(&q->done_lock, flags); + + if (vb && (vb->state == VB2_BUF_STATE_DONE + || vb->state == VB2_BUF_STATE_ERROR)) { + return (q->is_output) ? + POLLOUT | POLLWRNORM : + POLLIN | POLLRDNORM; + } + return 0; +} +EXPORT_SYMBOL_GPL(vb2_core_poll); + +/** + * struct vb2_fileio_buf - buffer context used by file io emulator + * + * vb2 provides a compatibility layer and emulator of file io (read and + * write) calls on top of streaming API. This structure is used for + * tracking context related to the buffers. + */ +struct vb2_fileio_buf { + void *vaddr; + unsigned int size; + unsigned int pos; + unsigned int queued:1; +}; + +/** + * struct vb2_fileio_data - queue context used by file io emulator + * + * @cur_index: the index of the buffer currently being read from or + * written to. If equal to q->num_buffers then a new buffer + * must be dequeued. + * @initial_index: in the read() case all buffers are queued up immediately + * in __vb2_init_fileio() and __vb2_perform_fileio() just cycles + * buffers. However, in the write() case no buffers are initially + * queued, instead whenever a buffer is full it is queued up by + * __vb2_perform_fileio(). Only once all available buffers have + * been queued up will __vb2_perform_fileio() start to dequeue + * buffers. This means that initially __vb2_perform_fileio() + * needs to know what buffer index to use when it is queuing up + * the buffers for the first time. That initial index is stored + * in this field. Once it is equal to q->num_buffers all + * available buffers have been queued and __vb2_perform_fileio() + * should start the normal dequeue/queue cycle. + * + * vb2 provides a compatibility layer and emulator of file io (read and + * write) calls on top of streaming API. For proper operation it required + * this structure to save the driver state between each call of the read + * or write function. + */ +struct vb2_fileio_data { + unsigned int count; + unsigned int type; + unsigned int memory; + struct vb2_fileio_buf bufs[VB2_MAX_FRAME]; + unsigned int cur_index; + unsigned int initial_index; + unsigned int q_count; + unsigned int dq_count; + unsigned read_once:1; + unsigned write_immediately:1; +}; + +/** + * __vb2_init_fileio() - initialize file io emulator + * @q: videobuf2 queue + * @read: mode selector (1 means read, 0 means write) + */ +static int __vb2_init_fileio(struct vb2_queue *q, int read) +{ + struct vb2_fileio_data *fileio; + int i, ret; + unsigned int count = 0; + + /* + * Sanity check + */ + if (WARN_ON((read && !(q->io_modes & VB2_READ)) || + (!read && !(q->io_modes & VB2_WRITE)))) + return -EINVAL; + + /* + * Check if device supports mapping buffers to kernel virtual space. + */ + if (!q->mem_ops->vaddr) + return -EBUSY; + + /* + * Check if streaming api has not been already activated. + */ + if (q->streaming || q->num_buffers > 0) + return -EBUSY; + + /* + * Start with count 1, driver can increase it in queue_setup() + */ + count = 1; + + dprintk(3, "setting up file io: mode %s, count %d, read_once %d, write_immediately %d\n", + (read) ? "read" : "write", count, q->fileio_read_once, + q->fileio_write_immediately); + + fileio = kzalloc(sizeof(*fileio), GFP_KERNEL); + if (fileio == NULL) + return -ENOMEM; + + fileio->read_once = q->fileio_read_once; + fileio->write_immediately = q->fileio_write_immediately; + + /* + * Request buffers and use MMAP type to force driver + * to allocate buffers by itself. + */ + fileio->count = count; + fileio->memory = VB2_MEMORY_MMAP; + fileio->type = q->type; + q->fileio = fileio; + ret = vb2_core_reqbufs(q, fileio->memory, &fileio->count); + if (ret) + goto err_kfree; + + /* + * Check if plane_count is correct + * (multiplane buffers are not supported). + */ + if (q->bufs[0]->num_planes != 1) { + ret = -EBUSY; + goto err_reqbufs; + } + + /* + * Get kernel address of each buffer. + */ + for (i = 0; i < q->num_buffers; i++) { + fileio->bufs[i].vaddr = vb2_plane_vaddr(q->bufs[i], 0); + if (fileio->bufs[i].vaddr == NULL) { + ret = -EINVAL; + goto err_reqbufs; + } + fileio->bufs[i].size = vb2_plane_size(q->bufs[i], 0); + } + + /* + * Read mode requires pre queuing of all buffers. + */ + if (read) { + /* + * Queue all buffers. + */ + for (i = 0; i < q->num_buffers; i++) { + ret = vb2_core_qbuf(q, i, NULL); + if (ret) + goto err_reqbufs; + fileio->bufs[i].queued = 1; + } + /* + * All buffers have been queued, so mark that by setting + * initial_index to q->num_buffers + */ + fileio->initial_index = q->num_buffers; + fileio->cur_index = q->num_buffers; + } + + /* + * Start streaming. + */ + ret = vb2_core_streamon(q, q->type); + if (ret) + goto err_reqbufs; + + return ret; + +err_reqbufs: + fileio->count = 0; + vb2_core_reqbufs(q, fileio->memory, &fileio->count); + +err_kfree: + q->fileio = NULL; + kfree(fileio); + return ret; +} + +/** + * __vb2_cleanup_fileio() - free resourced used by file io emulator + * @q: videobuf2 queue + */ +static int __vb2_cleanup_fileio(struct vb2_queue *q) +{ + struct vb2_fileio_data *fileio = q->fileio; + + if (fileio) { + vb2_core_streamoff(q, q->type); + q->fileio = NULL; + fileio->count = 0; + vb2_core_reqbufs(q, fileio->memory, &fileio->count); + kfree(fileio); + dprintk(3, "file io emulator closed\n"); + } + return 0; +} + +/** + * __vb2_perform_fileio() - perform a single file io (read or write) operation + * @q: videobuf2 queue + * @data: pointed to target userspace buffer + * @count: number of bytes to read or write + * @ppos: file handle position tracking pointer + * @nonblock: mode selector (1 means blocking calls, 0 means nonblocking) + * @read: access mode selector (1 means read, 0 means write) + */ +static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_t count, + loff_t *ppos, int nonblock, int read) +{ + struct vb2_fileio_data *fileio; + struct vb2_fileio_buf *buf; + bool is_multiplanar = q->is_multiplanar; + /* + * When using write() to write data to an output video node the vb2 core + * should copy timestamps if V4L2_BUF_FLAG_TIMESTAMP_COPY is set. Nobody + * else is able to provide this information with the write() operation. + */ + bool copy_timestamp = !read && q->copy_timestamp; + unsigned index; + int ret; + + dprintk(3, "mode %s, offset %ld, count %zd, %sblocking\n", + read ? "read" : "write", (long)*ppos, count, + nonblock ? "non" : ""); + + if (!data) + return -EINVAL; + + /* + * Initialize emulator on first call. + */ + if (!vb2_fileio_is_active(q)) { + ret = __vb2_init_fileio(q, read); + dprintk(3, "vb2_init_fileio result: %d\n", ret); + if (ret) + return ret; + } + fileio = q->fileio; + + /* + * Check if we need to dequeue the buffer. + */ + index = fileio->cur_index; + if (index >= q->num_buffers) { + struct vb2_buffer *b; + + /* + * Call vb2_dqbuf to get buffer back. + */ + ret = vb2_core_dqbuf(q, &index, NULL, nonblock); + dprintk(5, "vb2_dqbuf result: %d\n", ret); + if (ret) + return ret; + fileio->dq_count += 1; + + fileio->cur_index = index; + buf = &fileio->bufs[index]; + b = q->bufs[index]; + + /* + * Get number of bytes filled by the driver + */ + buf->pos = 0; + buf->queued = 0; + buf->size = read ? vb2_get_plane_payload(q->bufs[index], 0) + : vb2_plane_size(q->bufs[index], 0); + /* Compensate for data_offset on read in the multiplanar case. */ + if (is_multiplanar && read && + b->planes[0].data_offset < buf->size) { + buf->pos = b->planes[0].data_offset; + buf->size -= buf->pos; + } + } else { + buf = &fileio->bufs[index]; + } + + /* + * Limit count on last few bytes of the buffer. + */ + if (buf->pos + count > buf->size) { + count = buf->size - buf->pos; + dprintk(5, "reducing read count: %zd\n", count); + } + + /* + * Transfer data to userspace. + */ + dprintk(3, "copying %zd bytes - buffer %d, offset %u\n", + count, index, buf->pos); + if (read) + ret = copy_to_user(data, buf->vaddr + buf->pos, count); + else + ret = copy_from_user(buf->vaddr + buf->pos, data, count); + if (ret) { + dprintk(3, "error copying data\n"); + return -EFAULT; + } + + /* + * Update counters. + */ + buf->pos += count; + *ppos += count; + + /* + * Queue next buffer if required. + */ + if (buf->pos == buf->size || (!read && fileio->write_immediately)) { + struct vb2_buffer *b = q->bufs[index]; + + /* + * Check if this is the last buffer to read. + */ + if (read && fileio->read_once && fileio->dq_count == 1) { + dprintk(3, "read limit reached\n"); + return __vb2_cleanup_fileio(q); + } + + /* + * Call vb2_qbuf and give buffer to the driver. + */ + b->planes[0].bytesused = buf->pos; + + if (copy_timestamp) + b->timestamp = ktime_get_ns(); + ret = vb2_core_qbuf(q, index, NULL); + dprintk(5, "vb2_dbuf result: %d\n", ret); + if (ret) + return ret; + + /* + * Buffer has been queued, update the status + */ + buf->pos = 0; + buf->queued = 1; + buf->size = vb2_plane_size(q->bufs[index], 0); + fileio->q_count += 1; + /* + * If we are queuing up buffers for the first time, then + * increase initial_index by one. + */ + if (fileio->initial_index < q->num_buffers) + fileio->initial_index++; + /* + * The next buffer to use is either a buffer that's going to be + * queued for the first time (initial_index < q->num_buffers) + * or it is equal to q->num_buffers, meaning that the next + * time we need to dequeue a buffer since we've now queued up + * all the 'first time' buffers. + */ + fileio->cur_index = fileio->initial_index; + } + + /* + * Return proper number of bytes processed. + */ + if (ret == 0) + ret = count; + return ret; +} + +size_t vb2_read(struct vb2_queue *q, char __user *data, size_t count, + loff_t *ppos, int nonblocking) +{ + return __vb2_perform_fileio(q, data, count, ppos, nonblocking, 1); +} +EXPORT_SYMBOL_GPL(vb2_read); + +size_t vb2_write(struct vb2_queue *q, const char __user *data, size_t count, + loff_t *ppos, int nonblocking) +{ + return __vb2_perform_fileio(q, (char __user *) data, count, + ppos, nonblocking, 0); +} +EXPORT_SYMBOL_GPL(vb2_write); + +struct vb2_threadio_data { + struct task_struct *thread; + vb2_thread_fnc fnc; + void *priv; + bool stop; +}; + +static int vb2_thread(void *data) +{ + struct vb2_queue *q = data; + struct vb2_threadio_data *threadio = q->threadio; + bool copy_timestamp = false; + unsigned prequeue = 0; + unsigned index = 0; + int ret = 0; + + if (q->is_output) { + prequeue = q->num_buffers; + copy_timestamp = q->copy_timestamp; + } + + set_freezable(); + + for (;;) { + struct vb2_buffer *vb; + + /* + * Call vb2_dqbuf to get buffer back. + */ + if (prequeue) { + vb = q->bufs[index++]; + prequeue--; + } else { + call_void_qop(q, wait_finish, q); + if (!threadio->stop) + ret = vb2_core_dqbuf(q, &index, NULL, 0); + call_void_qop(q, wait_prepare, q); + dprintk(5, "file io: vb2_dqbuf result: %d\n", ret); + if (!ret) + vb = q->bufs[index]; + } + if (ret || threadio->stop) + break; + try_to_freeze(); + + if (vb->state != VB2_BUF_STATE_ERROR) + if (threadio->fnc(vb, threadio->priv)) + break; + call_void_qop(q, wait_finish, q); + if (copy_timestamp) + vb->timestamp = ktime_get_ns();; + if (!threadio->stop) + ret = vb2_core_qbuf(q, vb->index, NULL); + call_void_qop(q, wait_prepare, q); + if (ret || threadio->stop) + break; + } + + /* Hmm, linux becomes *very* unhappy without this ... */ + while (!kthread_should_stop()) { + set_current_state(TASK_INTERRUPTIBLE); + schedule(); + } + return 0; +} + +/* + * This function should not be used for anything else but the videobuf2-dvb + * support. If you think you have another good use-case for this, then please + * contact the linux-media mailinglist first. + */ +int vb2_thread_start(struct vb2_queue *q, vb2_thread_fnc fnc, void *priv, + const char *thread_name) +{ + struct vb2_threadio_data *threadio; + int ret = 0; + + if (q->threadio) + return -EBUSY; + if (vb2_is_busy(q)) + return -EBUSY; + if (WARN_ON(q->fileio)) + return -EBUSY; + + threadio = kzalloc(sizeof(*threadio), GFP_KERNEL); + if (threadio == NULL) + return -ENOMEM; + threadio->fnc = fnc; + threadio->priv = priv; + + ret = __vb2_init_fileio(q, !q->is_output); + dprintk(3, "file io: vb2_init_fileio result: %d\n", ret); + if (ret) + goto nomem; + q->threadio = threadio; + threadio->thread = kthread_run(vb2_thread, q, "vb2-%s", thread_name); + if (IS_ERR(threadio->thread)) { + ret = PTR_ERR(threadio->thread); + threadio->thread = NULL; + goto nothread; + } + return 0; + +nothread: + __vb2_cleanup_fileio(q); +nomem: + kfree(threadio); + return ret; +} +EXPORT_SYMBOL_GPL(vb2_thread_start); + +int vb2_thread_stop(struct vb2_queue *q) +{ + struct vb2_threadio_data *threadio = q->threadio; + int err; + + if (threadio == NULL) + return 0; + threadio->stop = true; + /* Wake up all pending sleeps in the thread */ + vb2_queue_error(q); + err = kthread_stop(threadio->thread); + __vb2_cleanup_fileio(q); + threadio->thread = NULL; + kfree(threadio); + q->threadio = NULL; + return err; +} +EXPORT_SYMBOL_GPL(vb2_thread_stop); + +MODULE_DESCRIPTION("Media buffer core framework"); MODULE_AUTHOR("Pawel Osciak <pawel@osciak.com>, Marek Szyprowski"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/v4l2-core/videobuf2-internal.h b/drivers/media/v4l2-core/videobuf2-internal.h deleted file mode 100644 index 79018c749..000000000 --- a/drivers/media/v4l2-core/videobuf2-internal.h +++ /dev/null @@ -1,161 +0,0 @@ -#ifndef _MEDIA_VIDEOBUF2_INTERNAL_H -#define _MEDIA_VIDEOBUF2_INTERNAL_H - -#include <linux/err.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <media/videobuf2-core.h> - -extern int vb2_debug; - -#define dprintk(level, fmt, arg...) \ - do { \ - if (vb2_debug >= level) \ - pr_info("vb2: %s: " fmt, __func__, ## arg); \ - } while (0) - -#ifdef CONFIG_VIDEO_ADV_DEBUG - -/* - * If advanced debugging is on, then count how often each op is called - * successfully, which can either be per-buffer or per-queue. - * - * This makes it easy to check that the 'init' and 'cleanup' - * (and variations thereof) stay balanced. - */ - -#define log_memop(vb, op) \ - dprintk(2, "call_memop(%p, %d, %s)%s\n", \ - (vb)->vb2_queue, (vb)->index, #op, \ - (vb)->vb2_queue->mem_ops->op ? "" : " (nop)") - -#define call_memop(vb, op, args...) \ -({ \ - struct vb2_queue *_q = (vb)->vb2_queue; \ - int err; \ - \ - log_memop(vb, op); \ - err = _q->mem_ops->op ? _q->mem_ops->op(args) : 0; \ - if (!err) \ - (vb)->cnt_mem_ ## op++; \ - err; \ -}) - -#define call_ptr_memop(vb, op, args...) \ -({ \ - struct vb2_queue *_q = (vb)->vb2_queue; \ - void *ptr; \ - \ - log_memop(vb, op); \ - ptr = _q->mem_ops->op ? _q->mem_ops->op(args) : NULL; \ - if (!IS_ERR_OR_NULL(ptr)) \ - (vb)->cnt_mem_ ## op++; \ - ptr; \ -}) - -#define call_void_memop(vb, op, args...) \ -({ \ - struct vb2_queue *_q = (vb)->vb2_queue; \ - \ - log_memop(vb, op); \ - if (_q->mem_ops->op) \ - _q->mem_ops->op(args); \ - (vb)->cnt_mem_ ## op++; \ -}) - -#define log_qop(q, op) \ - dprintk(2, "call_qop(%p, %s)%s\n", q, #op, \ - (q)->ops->op ? "" : " (nop)") - -#define call_qop(q, op, args...) \ -({ \ - int err; \ - \ - log_qop(q, op); \ - err = (q)->ops->op ? (q)->ops->op(args) : 0; \ - if (!err) \ - (q)->cnt_ ## op++; \ - err; \ -}) - -#define call_void_qop(q, op, args...) \ -({ \ - log_qop(q, op); \ - if ((q)->ops->op) \ - (q)->ops->op(args); \ - (q)->cnt_ ## op++; \ -}) - -#define log_vb_qop(vb, op, args...) \ - dprintk(2, "call_vb_qop(%p, %d, %s)%s\n", \ - (vb)->vb2_queue, (vb)->index, #op, \ - (vb)->vb2_queue->ops->op ? "" : " (nop)") - -#define call_vb_qop(vb, op, args...) \ -({ \ - int err; \ - \ - log_vb_qop(vb, op); \ - err = (vb)->vb2_queue->ops->op ? \ - (vb)->vb2_queue->ops->op(args) : 0; \ - if (!err) \ - (vb)->cnt_ ## op++; \ - err; \ -}) - -#define call_void_vb_qop(vb, op, args...) \ -({ \ - log_vb_qop(vb, op); \ - if ((vb)->vb2_queue->ops->op) \ - (vb)->vb2_queue->ops->op(args); \ - (vb)->cnt_ ## op++; \ -}) - -#else - -#define call_memop(vb, op, args...) \ - ((vb)->vb2_queue->mem_ops->op ? \ - (vb)->vb2_queue->mem_ops->op(args) : 0) - -#define call_ptr_memop(vb, op, args...) \ - ((vb)->vb2_queue->mem_ops->op ? \ - (vb)->vb2_queue->mem_ops->op(args) : NULL) - -#define call_void_memop(vb, op, args...) \ - do { \ - if ((vb)->vb2_queue->mem_ops->op) \ - (vb)->vb2_queue->mem_ops->op(args); \ - } while (0) - -#define call_qop(q, op, args...) \ - ((q)->ops->op ? (q)->ops->op(args) : 0) - -#define call_void_qop(q, op, args...) \ - do { \ - if ((q)->ops->op) \ - (q)->ops->op(args); \ - } while (0) - -#define call_vb_qop(vb, op, args...) \ - ((vb)->vb2_queue->ops->op ? (vb)->vb2_queue->ops->op(args) : 0) - -#define call_void_vb_qop(vb, op, args...) \ - do { \ - if ((vb)->vb2_queue->ops->op) \ - (vb)->vb2_queue->ops->op(args); \ - } while (0) - -#endif - -#define call_bufop(q, op, args...) \ -({ \ - int ret = 0; \ - if (q && q->buf_ops && q->buf_ops->op) \ - ret = q->buf_ops->op(args); \ - ret; \ -}) - -bool vb2_buffer_in_use(struct vb2_queue *q, struct vb2_buffer *vb); -int vb2_verify_memory_type(struct vb2_queue *q, - enum vb2_memory memory, unsigned int type); -#endif /* _MEDIA_VIDEOBUF2_INTERNAL_H */ diff --git a/drivers/media/v4l2-core/videobuf2-v4l2.c b/drivers/media/v4l2-core/videobuf2-v4l2.c index 502984c72..91f552124 100644 --- a/drivers/media/v4l2-core/videobuf2-v4l2.c +++ b/drivers/media/v4l2-core/videobuf2-v4l2.c @@ -31,7 +31,14 @@ #include <media/videobuf2-v4l2.h> -#include "videobuf2-internal.h" +static int debug; +module_param(debug, int, 0644); + +#define dprintk(level, fmt, arg...) \ + do { \ + if (debug >= level) \ + pr_info("vb2-v4l2: %s: " fmt, __func__, ## arg); \ + } while (0) /* Flags that are set by the vb2 core */ #define V4L2_BUFFER_MASK_FLAGS (V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | \ @@ -52,7 +59,7 @@ static int __verify_planes_array(struct vb2_buffer *vb, const struct v4l2_buffer return 0; /* Is memory for copying plane information present? */ - if (NULL == b->m.planes) { + if (b->m.planes == NULL) { dprintk(1, "multi-planar buffer passed but " "planes array not provided\n"); return -EINVAL; @@ -107,7 +114,7 @@ static int __verify_length(struct vb2_buffer *vb, const struct v4l2_buffer *b) return 0; } -static int __set_timestamp(struct vb2_buffer *vb, const void *pb) +static void __copy_timestamp(struct vb2_buffer *vb, const void *pb) { const struct v4l2_buffer *b = pb; struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); @@ -118,14 +125,12 @@ static int __set_timestamp(struct vb2_buffer *vb, const void *pb) * For output buffers copy the timestamp if needed, * and the timecode field and flag if needed. */ - if ((q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) == - V4L2_BUF_FLAG_TIMESTAMP_COPY) - vbuf->timestamp = b->timestamp; + if (q->copy_timestamp) + vb->timestamp = timeval_to_ns(&b->timestamp); vbuf->flags |= b->flags & V4L2_BUF_FLAG_TIMECODE; if (b->flags & V4L2_BUF_FLAG_TIMECODE) vbuf->timecode = b->timecode; } - return 0; }; static void vb2_warn_zero_bytesused(struct vb2_buffer *vb) @@ -176,7 +181,7 @@ static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b, * __fill_v4l2_buffer() - fill in a struct v4l2_buffer with information to be * returned to userspace */ -static int __fill_v4l2_buffer(struct vb2_buffer *vb, void *pb) +static void __fill_v4l2_buffer(struct vb2_buffer *vb, void *pb) { struct v4l2_buffer *b = pb; struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); @@ -191,7 +196,7 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, void *pb) b->flags = vbuf->flags; b->field = vbuf->field; - b->timestamp = vbuf->timestamp; + b->timestamp = ns_to_timeval(vb->timestamp); b->timecode = vbuf->timecode; b->sequence = vbuf->sequence; b->reserved2 = 0; @@ -238,8 +243,7 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, void *pb) */ b->flags &= ~V4L2_BUFFER_MASK_FLAGS; b->flags |= q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK; - if ((q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) != - V4L2_BUF_FLAG_TIMESTAMP_COPY) { + if (!q->copy_timestamp) { /* * For non-COPY timestamps, drop timestamp source bits * and obtain the timestamp source from the queue. @@ -272,7 +276,10 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, void *pb) if (vb2_buffer_in_use(q, vb)) b->flags |= V4L2_BUF_FLAG_MAPPED; - return 0; + if (!q->is_output && + b->flags & V4L2_BUF_FLAG_DONE && + b->flags & V4L2_BUF_FLAG_LAST) + q->last_buffer_dequeued = true; } /** @@ -308,8 +315,7 @@ static int __fill_vb2_buffer(struct vb2_buffer *vb, "for an output buffer\n"); return -EINVAL; } - vbuf->timestamp.tv_sec = 0; - vbuf->timestamp.tv_usec = 0; + vb->timestamp = 0; vbuf->sequence = 0; if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) { @@ -404,8 +410,7 @@ static int __fill_vb2_buffer(struct vb2_buffer *vb, /* Zero flags that the vb2 core handles */ vbuf->flags = b->flags & ~V4L2_BUFFER_MASK_FLAGS; - if ((vb->vb2_queue->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) != - V4L2_BUF_FLAG_TIMESTAMP_COPY || !V4L2_TYPE_IS_OUTPUT(b->type)) { + if (!vb->vb2_queue->copy_timestamp || !V4L2_TYPE_IS_OUTPUT(b->type)) { /* * Non-COPY timestamps and non-OUTPUT queues will get * their timestamp and timestamp source flags from the @@ -434,7 +439,7 @@ static int __fill_vb2_buffer(struct vb2_buffer *vb, static const struct vb2_buf_ops v4l2_buf_ops = { .fill_user_buffer = __fill_v4l2_buffer, .fill_vb2_buffer = __fill_vb2_buffer, - .set_timestamp = __set_timestamp, + .copy_timestamp = __copy_timestamp, }; /** @@ -466,8 +471,9 @@ int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b) } vb = q->bufs[b->index]; ret = __verify_planes_array(vb, b); - - return ret ? ret : vb2_core_querybuf(q, b->index, b); + if (!ret) + vb2_core_querybuf(q, b->index, b); + return ret; } EXPORT_SYMBOL(vb2_querybuf); @@ -525,14 +531,52 @@ EXPORT_SYMBOL_GPL(vb2_prepare_buf); */ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create) { - int ret = vb2_verify_memory_type(q, create->memory, - create->format.type); + unsigned requested_planes = 1; + unsigned requested_sizes[VIDEO_MAX_PLANES]; + struct v4l2_format *f = &create->format; + int ret = vb2_verify_memory_type(q, create->memory, f->type); + unsigned i; create->index = q->num_buffers; if (create->count == 0) return ret != -EBUSY ? ret : 0; + + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + requested_planes = f->fmt.pix_mp.num_planes; + if (requested_planes == 0 || + requested_planes > VIDEO_MAX_PLANES) + return -EINVAL; + for (i = 0; i < requested_planes; i++) + requested_sizes[i] = + f->fmt.pix_mp.plane_fmt[i].sizeimage; + break; + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + requested_sizes[0] = f->fmt.pix.sizeimage; + break; + case V4L2_BUF_TYPE_VBI_CAPTURE: + case V4L2_BUF_TYPE_VBI_OUTPUT: + requested_sizes[0] = f->fmt.vbi.samples_per_line * + (f->fmt.vbi.count[0] + f->fmt.vbi.count[1]); + break; + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: + requested_sizes[0] = f->fmt.sliced.io_size; + break; + case V4L2_BUF_TYPE_SDR_CAPTURE: + case V4L2_BUF_TYPE_SDR_OUTPUT: + requested_sizes[0] = f->fmt.sdr.buffersize; + break; + default: + return -EINVAL; + } + for (i = 0; i < requested_planes; i++) + if (requested_sizes[i] == 0) + return -EINVAL; return ret ? ret : vb2_core_create_bufs(q, create->memory, - &create->count, &create->format); + &create->count, requested_planes, requested_sizes); } EXPORT_SYMBOL_GPL(vb2_create_bufs); @@ -581,11 +625,7 @@ static int vb2_internal_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, return -EINVAL; } - ret = vb2_core_dqbuf(q, b, nonblocking); - - if (!ret && !q->is_output && - b->flags & V4L2_BUF_FLAG_LAST) - q->last_buffer_dequeued = true; + ret = vb2_core_dqbuf(q, NULL, b, nonblocking); return ret; } @@ -723,14 +763,13 @@ int vb2_queue_init(struct vb2_queue *q) q->buf_ops = &v4l2_buf_ops; q->is_multiplanar = V4L2_TYPE_IS_MULTIPLANAR(q->type); q->is_output = V4L2_TYPE_IS_OUTPUT(q->type); + q->copy_timestamp = (q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) + == V4L2_BUF_FLAG_TIMESTAMP_COPY; return vb2_core_queue_init(q); } EXPORT_SYMBOL_GPL(vb2_queue_init); -static int __vb2_init_fileio(struct vb2_queue *q, int read); -static int __vb2_cleanup_fileio(struct vb2_queue *q); - /** * vb2_queue_release() - stop streaming, release the queue and free memory * @q: videobuf2 queue @@ -741,7 +780,6 @@ static int __vb2_cleanup_fileio(struct vb2_queue *q); */ void vb2_queue_release(struct vb2_queue *q) { - __vb2_cleanup_fileio(q); vb2_core_queue_release(q); } EXPORT_SYMBOL_GPL(vb2_queue_release); @@ -769,9 +807,7 @@ unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait) { struct video_device *vfd = video_devdata(file); unsigned long req_events = poll_requested_events(wait); - struct vb2_buffer *vb = NULL; unsigned int res = 0; - unsigned long flags; if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) { struct v4l2_fh *fh = file->private_data; @@ -782,611 +818,18 @@ unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait) poll_wait(file, &fh->wait, wait); } - if (!q->is_output && !(req_events & (POLLIN | POLLRDNORM))) - return res; - if (q->is_output && !(req_events & (POLLOUT | POLLWRNORM))) - return res; - - /* - * Start file I/O emulator only if streaming API has not been used yet. - */ - if (q->num_buffers == 0 && !vb2_fileio_is_active(q)) { - if (!q->is_output && (q->io_modes & VB2_READ) && - (req_events & (POLLIN | POLLRDNORM))) { - if (__vb2_init_fileio(q, 1)) - return res | POLLERR; - } - if (q->is_output && (q->io_modes & VB2_WRITE) && - (req_events & (POLLOUT | POLLWRNORM))) { - if (__vb2_init_fileio(q, 0)) - return res | POLLERR; - /* - * Write to OUTPUT queue can be done immediately. - */ - return res | POLLOUT | POLLWRNORM; - } - } - - /* - * There is nothing to wait for if the queue isn't streaming, or if the - * error flag is set. - */ - if (!vb2_is_streaming(q) || q->error) - return res | POLLERR; /* * For compatibility with vb1: if QBUF hasn't been called yet, then * return POLLERR as well. This only affects capture queues, output * queues will always initialize waiting_for_buffers to false. */ - if (q->waiting_for_buffers) - return res | POLLERR; - - /* - * For output streams you can call write() as long as there are fewer - * buffers queued than there are buffers available. - */ - if (q->is_output && q->fileio && q->queued_count < q->num_buffers) - return res | POLLOUT | POLLWRNORM; - - if (list_empty(&q->done_list)) { - /* - * If the last buffer was dequeued from a capture queue, - * return immediately. DQBUF will return -EPIPE. - */ - if (q->last_buffer_dequeued) - return res | POLLIN | POLLRDNORM; - - poll_wait(file, &q->done_wq, wait); - } + if (q->waiting_for_buffers && (req_events & (POLLIN | POLLRDNORM))) + return POLLERR; - /* - * Take first buffer available for dequeuing. - */ - spin_lock_irqsave(&q->done_lock, flags); - if (!list_empty(&q->done_list)) - vb = list_first_entry(&q->done_list, struct vb2_buffer, - done_entry); - spin_unlock_irqrestore(&q->done_lock, flags); - - if (vb && (vb->state == VB2_BUF_STATE_DONE - || vb->state == VB2_BUF_STATE_ERROR)) { - return (q->is_output) ? - res | POLLOUT | POLLWRNORM : - res | POLLIN | POLLRDNORM; - } - return res; + return res | vb2_core_poll(q, file, wait); } EXPORT_SYMBOL_GPL(vb2_poll); -/** - * struct vb2_fileio_buf - buffer context used by file io emulator - * - * vb2 provides a compatibility layer and emulator of file io (read and - * write) calls on top of streaming API. This structure is used for - * tracking context related to the buffers. - */ -struct vb2_fileio_buf { - void *vaddr; - unsigned int size; - unsigned int pos; - unsigned int queued:1; -}; - -/** - * struct vb2_fileio_data - queue context used by file io emulator - * - * @cur_index: the index of the buffer currently being read from or - * written to. If equal to q->num_buffers then a new buffer - * must be dequeued. - * @initial_index: in the read() case all buffers are queued up immediately - * in __vb2_init_fileio() and __vb2_perform_fileio() just cycles - * buffers. However, in the write() case no buffers are initially - * queued, instead whenever a buffer is full it is queued up by - * __vb2_perform_fileio(). Only once all available buffers have - * been queued up will __vb2_perform_fileio() start to dequeue - * buffers. This means that initially __vb2_perform_fileio() - * needs to know what buffer index to use when it is queuing up - * the buffers for the first time. That initial index is stored - * in this field. Once it is equal to q->num_buffers all - * available buffers have been queued and __vb2_perform_fileio() - * should start the normal dequeue/queue cycle. - * - * vb2 provides a compatibility layer and emulator of file io (read and - * write) calls on top of streaming API. For proper operation it required - * this structure to save the driver state between each call of the read - * or write function. - */ -struct vb2_fileio_data { - struct v4l2_requestbuffers req; - struct v4l2_plane p; - struct v4l2_buffer b; - struct vb2_fileio_buf bufs[VB2_MAX_FRAME]; - unsigned int cur_index; - unsigned int initial_index; - unsigned int q_count; - unsigned int dq_count; - unsigned read_once:1; - unsigned write_immediately:1; -}; - -/** - * __vb2_init_fileio() - initialize file io emulator - * @q: videobuf2 queue - * @read: mode selector (1 means read, 0 means write) - */ -static int __vb2_init_fileio(struct vb2_queue *q, int read) -{ - struct vb2_fileio_data *fileio; - int i, ret; - unsigned int count = 0; - - /* - * Sanity check - */ - if (WARN_ON((read && !(q->io_modes & VB2_READ)) || - (!read && !(q->io_modes & VB2_WRITE)))) - return -EINVAL; - - /* - * Check if device supports mapping buffers to kernel virtual space. - */ - if (!q->mem_ops->vaddr) - return -EBUSY; - - /* - * Check if streaming api has not been already activated. - */ - if (q->streaming || q->num_buffers > 0) - return -EBUSY; - - /* - * Start with count 1, driver can increase it in queue_setup() - */ - count = 1; - - dprintk(3, "setting up file io: mode %s, count %d, read_once %d, write_immediately %d\n", - (read) ? "read" : "write", count, q->fileio_read_once, - q->fileio_write_immediately); - - fileio = kzalloc(sizeof(struct vb2_fileio_data), GFP_KERNEL); - if (fileio == NULL) - return -ENOMEM; - - fileio->read_once = q->fileio_read_once; - fileio->write_immediately = q->fileio_write_immediately; - - /* - * Request buffers and use MMAP type to force driver - * to allocate buffers by itself. - */ - fileio->req.count = count; - fileio->req.memory = VB2_MEMORY_MMAP; - fileio->req.type = q->type; - q->fileio = fileio; - ret = vb2_core_reqbufs(q, fileio->req.memory, &fileio->req.count); - if (ret) - goto err_kfree; - - /* - * Check if plane_count is correct - * (multiplane buffers are not supported). - */ - if (q->bufs[0]->num_planes != 1) { - ret = -EBUSY; - goto err_reqbufs; - } - - /* - * Get kernel address of each buffer. - */ - for (i = 0; i < q->num_buffers; i++) { - fileio->bufs[i].vaddr = vb2_plane_vaddr(q->bufs[i], 0); - if (fileio->bufs[i].vaddr == NULL) { - ret = -EINVAL; - goto err_reqbufs; - } - fileio->bufs[i].size = vb2_plane_size(q->bufs[i], 0); - } - - /* - * Read mode requires pre queuing of all buffers. - */ - if (read) { - bool is_multiplanar = q->is_multiplanar; - - /* - * Queue all buffers. - */ - for (i = 0; i < q->num_buffers; i++) { - struct v4l2_buffer *b = &fileio->b; - - memset(b, 0, sizeof(*b)); - b->type = q->type; - if (is_multiplanar) { - memset(&fileio->p, 0, sizeof(fileio->p)); - b->m.planes = &fileio->p; - b->length = 1; - } - b->memory = q->memory; - b->index = i; - ret = vb2_internal_qbuf(q, b); - if (ret) - goto err_reqbufs; - fileio->bufs[i].queued = 1; - } - /* - * All buffers have been queued, so mark that by setting - * initial_index to q->num_buffers - */ - fileio->initial_index = q->num_buffers; - fileio->cur_index = q->num_buffers; - } - - /* - * Start streaming. - */ - ret = vb2_core_streamon(q, q->type); - if (ret) - goto err_reqbufs; - - return ret; - -err_reqbufs: - fileio->req.count = 0; - vb2_core_reqbufs(q, fileio->req.memory, &fileio->req.count); - -err_kfree: - q->fileio = NULL; - kfree(fileio); - return ret; -} - -/** - * __vb2_cleanup_fileio() - free resourced used by file io emulator - * @q: videobuf2 queue - */ -static int __vb2_cleanup_fileio(struct vb2_queue *q) -{ - struct vb2_fileio_data *fileio = q->fileio; - - if (fileio) { - vb2_core_streamoff(q, q->type); - q->fileio = NULL; - fileio->req.count = 0; - vb2_reqbufs(q, &fileio->req); - kfree(fileio); - dprintk(3, "file io emulator closed\n"); - } - return 0; -} - -/** - * __vb2_perform_fileio() - perform a single file io (read or write) operation - * @q: videobuf2 queue - * @data: pointed to target userspace buffer - * @count: number of bytes to read or write - * @ppos: file handle position tracking pointer - * @nonblock: mode selector (1 means blocking calls, 0 means nonblocking) - * @read: access mode selector (1 means read, 0 means write) - */ -static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_t count, - loff_t *ppos, int nonblock, int read) -{ - struct vb2_fileio_data *fileio; - struct vb2_fileio_buf *buf; - bool is_multiplanar = q->is_multiplanar; - /* - * When using write() to write data to an output video node the vb2 core - * should set timestamps if V4L2_BUF_FLAG_TIMESTAMP_COPY is set. Nobody - * else is able to provide this information with the write() operation. - */ - bool set_timestamp = !read && - (q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) == - V4L2_BUF_FLAG_TIMESTAMP_COPY; - int ret, index; - - dprintk(3, "mode %s, offset %ld, count %zd, %sblocking\n", - read ? "read" : "write", (long)*ppos, count, - nonblock ? "non" : ""); - - if (!data) - return -EINVAL; - - /* - * Initialize emulator on first call. - */ - if (!vb2_fileio_is_active(q)) { - ret = __vb2_init_fileio(q, read); - dprintk(3, "vb2_init_fileio result: %d\n", ret); - if (ret) - return ret; - } - fileio = q->fileio; - - /* - * Check if we need to dequeue the buffer. - */ - index = fileio->cur_index; - if (index >= q->num_buffers) { - /* - * Call vb2_dqbuf to get buffer back. - */ - memset(&fileio->b, 0, sizeof(fileio->b)); - fileio->b.type = q->type; - fileio->b.memory = q->memory; - if (is_multiplanar) { - memset(&fileio->p, 0, sizeof(fileio->p)); - fileio->b.m.planes = &fileio->p; - fileio->b.length = 1; - } - ret = vb2_internal_dqbuf(q, &fileio->b, nonblock); - dprintk(5, "vb2_dqbuf result: %d\n", ret); - if (ret) - return ret; - fileio->dq_count += 1; - - fileio->cur_index = index = fileio->b.index; - buf = &fileio->bufs[index]; - - /* - * Get number of bytes filled by the driver - */ - buf->pos = 0; - buf->queued = 0; - buf->size = read ? vb2_get_plane_payload(q->bufs[index], 0) - : vb2_plane_size(q->bufs[index], 0); - /* Compensate for data_offset on read in the multiplanar case. */ - if (is_multiplanar && read && - fileio->b.m.planes[0].data_offset < buf->size) { - buf->pos = fileio->b.m.planes[0].data_offset; - buf->size -= buf->pos; - } - } else { - buf = &fileio->bufs[index]; - } - - /* - * Limit count on last few bytes of the buffer. - */ - if (buf->pos + count > buf->size) { - count = buf->size - buf->pos; - dprintk(5, "reducing read count: %zd\n", count); - } - - /* - * Transfer data to userspace. - */ - dprintk(3, "copying %zd bytes - buffer %d, offset %u\n", - count, index, buf->pos); - if (read) - ret = copy_to_user(data, buf->vaddr + buf->pos, count); - else - ret = copy_from_user(buf->vaddr + buf->pos, data, count); - if (ret) { - dprintk(3, "error copying data\n"); - return -EFAULT; - } - - /* - * Update counters. - */ - buf->pos += count; - *ppos += count; - - /* - * Queue next buffer if required. - */ - if (buf->pos == buf->size || (!read && fileio->write_immediately)) { - /* - * Check if this is the last buffer to read. - */ - if (read && fileio->read_once && fileio->dq_count == 1) { - dprintk(3, "read limit reached\n"); - return __vb2_cleanup_fileio(q); - } - - /* - * Call vb2_qbuf and give buffer to the driver. - */ - memset(&fileio->b, 0, sizeof(fileio->b)); - fileio->b.type = q->type; - fileio->b.memory = q->memory; - fileio->b.index = index; - fileio->b.bytesused = buf->pos; - if (is_multiplanar) { - memset(&fileio->p, 0, sizeof(fileio->p)); - fileio->p.bytesused = buf->pos; - fileio->b.m.planes = &fileio->p; - fileio->b.length = 1; - } - if (set_timestamp) - v4l2_get_timestamp(&fileio->b.timestamp); - ret = vb2_internal_qbuf(q, &fileio->b); - dprintk(5, "vb2_dbuf result: %d\n", ret); - if (ret) - return ret; - - /* - * Buffer has been queued, update the status - */ - buf->pos = 0; - buf->queued = 1; - buf->size = vb2_plane_size(q->bufs[index], 0); - fileio->q_count += 1; - /* - * If we are queuing up buffers for the first time, then - * increase initial_index by one. - */ - if (fileio->initial_index < q->num_buffers) - fileio->initial_index++; - /* - * The next buffer to use is either a buffer that's going to be - * queued for the first time (initial_index < q->num_buffers) - * or it is equal to q->num_buffers, meaning that the next - * time we need to dequeue a buffer since we've now queued up - * all the 'first time' buffers. - */ - fileio->cur_index = fileio->initial_index; - } - - /* - * Return proper number of bytes processed. - */ - if (ret == 0) - ret = count; - return ret; -} - -size_t vb2_read(struct vb2_queue *q, char __user *data, size_t count, - loff_t *ppos, int nonblocking) -{ - return __vb2_perform_fileio(q, data, count, ppos, nonblocking, 1); -} -EXPORT_SYMBOL_GPL(vb2_read); - -size_t vb2_write(struct vb2_queue *q, const char __user *data, size_t count, - loff_t *ppos, int nonblocking) -{ - return __vb2_perform_fileio(q, (char __user *) data, count, - ppos, nonblocking, 0); -} -EXPORT_SYMBOL_GPL(vb2_write); - -struct vb2_threadio_data { - struct task_struct *thread; - vb2_thread_fnc fnc; - void *priv; - bool stop; -}; - -static int vb2_thread(void *data) -{ - struct vb2_queue *q = data; - struct vb2_threadio_data *threadio = q->threadio; - struct vb2_fileio_data *fileio = q->fileio; - bool set_timestamp = false; - int prequeue = 0; - int index = 0; - int ret = 0; - - if (q->is_output) { - prequeue = q->num_buffers; - set_timestamp = - (q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) == - V4L2_BUF_FLAG_TIMESTAMP_COPY; - } - - set_freezable(); - - for (;;) { - struct vb2_buffer *vb; - - /* - * Call vb2_dqbuf to get buffer back. - */ - memset(&fileio->b, 0, sizeof(fileio->b)); - fileio->b.type = q->type; - fileio->b.memory = q->memory; - if (prequeue) { - fileio->b.index = index++; - prequeue--; - } else { - call_void_qop(q, wait_finish, q); - if (!threadio->stop) - ret = vb2_internal_dqbuf(q, &fileio->b, 0); - call_void_qop(q, wait_prepare, q); - dprintk(5, "file io: vb2_dqbuf result: %d\n", ret); - } - if (ret || threadio->stop) - break; - try_to_freeze(); - - vb = q->bufs[fileio->b.index]; - if (!(fileio->b.flags & V4L2_BUF_FLAG_ERROR)) - if (threadio->fnc(vb, threadio->priv)) - break; - call_void_qop(q, wait_finish, q); - if (set_timestamp) - v4l2_get_timestamp(&fileio->b.timestamp); - if (!threadio->stop) - ret = vb2_internal_qbuf(q, &fileio->b); - call_void_qop(q, wait_prepare, q); - if (ret || threadio->stop) - break; - } - - /* Hmm, linux becomes *very* unhappy without this ... */ - while (!kthread_should_stop()) { - set_current_state(TASK_INTERRUPTIBLE); - schedule(); - } - return 0; -} - -/* - * This function should not be used for anything else but the videobuf2-dvb - * support. If you think you have another good use-case for this, then please - * contact the linux-media mailinglist first. - */ -int vb2_thread_start(struct vb2_queue *q, vb2_thread_fnc fnc, void *priv, - const char *thread_name) -{ - struct vb2_threadio_data *threadio; - int ret = 0; - - if (q->threadio) - return -EBUSY; - if (vb2_is_busy(q)) - return -EBUSY; - if (WARN_ON(q->fileio)) - return -EBUSY; - - threadio = kzalloc(sizeof(*threadio), GFP_KERNEL); - if (threadio == NULL) - return -ENOMEM; - threadio->fnc = fnc; - threadio->priv = priv; - - ret = __vb2_init_fileio(q, !q->is_output); - dprintk(3, "file io: vb2_init_fileio result: %d\n", ret); - if (ret) - goto nomem; - q->threadio = threadio; - threadio->thread = kthread_run(vb2_thread, q, "vb2-%s", thread_name); - if (IS_ERR(threadio->thread)) { - ret = PTR_ERR(threadio->thread); - threadio->thread = NULL; - goto nothread; - } - return 0; - -nothread: - __vb2_cleanup_fileio(q); -nomem: - kfree(threadio); - return ret; -} -EXPORT_SYMBOL_GPL(vb2_thread_start); - -int vb2_thread_stop(struct vb2_queue *q) -{ - struct vb2_threadio_data *threadio = q->threadio; - int err; - - if (threadio == NULL) - return 0; - threadio->stop = true; - /* Wake up all pending sleeps in the thread */ - vb2_queue_error(q); - err = kthread_stop(threadio->thread); - __vb2_cleanup_fileio(q); - threadio->thread = NULL; - kfree(threadio); - q->threadio = NULL; - return err; -} -EXPORT_SYMBOL_GPL(vb2_thread_stop); - /* * The following functions are not part of the vb2 core API, but are helper * functions that plug into struct v4l2_ioctl_ops, struct v4l2_file_operations @@ -1440,8 +883,8 @@ int vb2_ioctl_create_bufs(struct file *file, void *priv, return res; if (vb2_queue_is_busy(vdev, file)) return -EBUSY; - res = vb2_core_create_bufs(vdev->queue, p->memory, &p->count, - &p->format); + + res = vb2_create_bufs(vdev->queue, p); if (res == 0) vdev->queue->owner = file->private_data; return res; |