Module Name:    src
Committed By:   riastradh
Date:           Sun Dec 19 01:56:33 UTC 2021

Modified Files:
        src/sys/external/bsd/drm2/dist/include/drm: drmP.h drm_drv.h
            drm_vblank.h

Log Message:
Move drm_device ifdef goo to drm_drv.h

And drm vblank stuff to drm_vblank.h

Author: Maya Rashish <m...@netbsd.org>


To generate a diff of this commit:
cvs rdiff -u -r1.52 -r1.53 src/sys/external/bsd/drm2/dist/include/drm/drmP.h
cvs rdiff -u -r1.3 -r1.4 src/sys/external/bsd/drm2/dist/include/drm/drm_drv.h
cvs rdiff -u -r1.6 -r1.7 \
    src/sys/external/bsd/drm2/dist/include/drm/drm_vblank.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/external/bsd/drm2/dist/include/drm/drmP.h
diff -u src/sys/external/bsd/drm2/dist/include/drm/drmP.h:1.52 src/sys/external/bsd/drm2/dist/include/drm/drmP.h:1.53
--- src/sys/external/bsd/drm2/dist/include/drm/drmP.h:1.52	Sun Dec 19 01:56:24 2021
+++ src/sys/external/bsd/drm2/dist/include/drm/drmP.h	Sun Dec 19 01:56:33 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: drmP.h,v 1.52 2021/12/19 01:56:24 riastradh Exp $	*/
+/*	$NetBSD: drmP.h,v 1.53 2021/12/19 01:56:33 riastradh Exp $	*/
 
 /*
  * Internal Header for the Direct Rendering Manager
@@ -263,288 +263,6 @@ struct drm_master {
 	void *driver_priv;
 };
 
-/* Size of ringbuffer for vblank timestamps. Just double-buffer
- * in initial implementation.
- */
-#define DRM_VBLANKTIME_RBSIZE 2
-
-/* Flags and return codes for get_vblank_timestamp() driver function. */
-#define DRM_CALLED_FROM_VBLIRQ 1
-#define DRM_VBLANKTIME_SCANOUTPOS_METHOD (1 << 0)
-#define DRM_VBLANKTIME_IN_VBLANK         (1 << 1)
-
-/* get_scanout_position() return flags */
-#define DRM_SCANOUTPOS_VALID        (1 << 0)
-#define DRM_SCANOUTPOS_IN_VBLANK    (1 << 1)
-#define DRM_SCANOUTPOS_ACCURATE     (1 << 2)
-
-/**
- * DRM driver structure. This structure represent the common code for
- * a family of cards. There will one drm_device for each card present
- * in this family
- */
-struct drm_driver {
-	int (*load) (struct drm_device *, unsigned long flags);
-	int (*firstopen) (struct drm_device *);
-	int (*open) (struct drm_device *, struct drm_file *);
-	void (*preclose) (struct drm_device *, struct drm_file *file_priv);
-	void (*postclose) (struct drm_device *, struct drm_file *);
-	void (*lastclose) (struct drm_device *);
-	int (*unload) (struct drm_device *);
-	int (*suspend) (struct drm_device *, pm_message_t state);
-	int (*resume) (struct drm_device *);
-	int (*dma_ioctl) (struct drm_device *dev, void *data, struct drm_file *file_priv);
-	int (*dma_quiescent) (struct drm_device *);
-	int (*context_dtor) (struct drm_device *dev, int context);
-	int (*set_busid)(struct drm_device *dev, struct drm_master *master);
-	int (*set_unique)(struct drm_device *dev, struct drm_master *master,
-	    struct drm_unique *);
-
-	/**
-	 * get_vblank_counter - get raw hardware vblank counter
-	 * @dev: DRM device
-	 * @pipe: counter to fetch
-	 *
-	 * Driver callback for fetching a raw hardware vblank counter for @crtc.
-	 * If a device doesn't have a hardware counter, the driver can simply
-	 * return the value of drm_vblank_count. The DRM core will account for
-	 * missed vblank events while interrupts where disabled based on system
-	 * timestamps.
-	 *
-	 * Wraparound handling and loss of events due to modesetting is dealt
-	 * with in the DRM core code.
-	 *
-	 * RETURNS
-	 * Raw vblank counter value.
-	 */
-	u32 (*get_vblank_counter) (struct drm_device *dev, unsigned int pipe);
-
-	/**
-	 * enable_vblank - enable vblank interrupt events
-	 * @dev: DRM device
-	 * @pipe: which irq to enable
-	 *
-	 * Enable vblank interrupts for @crtc.  If the device doesn't have
-	 * a hardware vblank counter, this routine should be a no-op, since
-	 * interrupts will have to stay on to keep the count accurate.
-	 *
-	 * RETURNS
-	 * Zero on success, appropriate errno if the given @crtc's vblank
-	 * interrupt cannot be enabled.
-	 */
-	int (*enable_vblank) (struct drm_device *dev, unsigned int pipe);
-
-	/**
-	 * disable_vblank - disable vblank interrupt events
-	 * @dev: DRM device
-	 * @pipe: which irq to enable
-	 *
-	 * Disable vblank interrupts for @crtc.  If the device doesn't have
-	 * a hardware vblank counter, this routine should be a no-op, since
-	 * interrupts will have to stay on to keep the count accurate.
-	 */
-	void (*disable_vblank) (struct drm_device *dev, unsigned int pipe);
-
-	/**
-	 * Called by \c drm_device_is_agp.  Typically used to determine if a
-	 * card is really attached to AGP or not.
-	 *
-	 * \param dev  DRM device handle
-	 *
-	 * \returns
-	 * One of three values is returned depending on whether or not the
-	 * card is absolutely \b not AGP (return of 0), absolutely \b is AGP
-	 * (return of 1), or may or may not be AGP (return of 2).
-	 */
-	int (*device_is_agp) (struct drm_device *dev);
-
-	/**
-	 * Called by vblank timestamping code.
-	 *
-	 * Return the current display scanout position from a crtc, and an
-	 * optional accurate ktime_get timestamp of when position was measured.
-	 *
-	 * \param dev  DRM device.
-	 * \param pipe Id of the crtc to query.
-	 * \param flags Flags from the caller (DRM_CALLED_FROM_VBLIRQ or 0).
-	 * \param *vpos Target location for current vertical scanout position.
-	 * \param *hpos Target location for current horizontal scanout position.
-	 * \param *stime Target location for timestamp taken immediately before
-	 *               scanout position query. Can be NULL to skip timestamp.
-	 * \param *etime Target location for timestamp taken immediately after
-	 *               scanout position query. Can be NULL to skip timestamp.
-	 * \param mode Current display timings.
-	 *
-	 * Returns vpos as a positive number while in active scanout area.
-	 * Returns vpos as a negative number inside vblank, counting the number
-	 * of scanlines to go until end of vblank, e.g., -1 means "one scanline
-	 * until start of active scanout / end of vblank."
-	 *
-	 * \return Flags, or'ed together as follows:
-	 *
-	 * DRM_SCANOUTPOS_VALID = Query successful.
-	 * DRM_SCANOUTPOS_INVBL = Inside vblank.
-	 * DRM_SCANOUTPOS_ACCURATE = Returned position is accurate. A lack of
-	 * this flag means that returned position may be offset by a constant
-	 * but unknown small number of scanlines wrt. real scanout position.
-	 *
-	 */
-	int (*get_scanout_position) (struct drm_device *dev, unsigned int pipe,
-				     unsigned int flags, int *vpos, int *hpos,
-				     ktime_t *stime, ktime_t *etime,
-				     const struct drm_display_mode *mode);
-
-	/**
-	 * Called by \c drm_get_last_vbltimestamp. Should return a precise
-	 * timestamp when the most recent VBLANK interval ended or will end.
-	 *
-	 * Specifically, the timestamp in @vblank_time should correspond as
-	 * closely as possible to the time when the first video scanline of
-	 * the video frame after the end of VBLANK will start scanning out,
-	 * the time immediately after end of the VBLANK interval. If the
-	 * @crtc is currently inside VBLANK, this will be a time in the future.
-	 * If the @crtc is currently scanning out a frame, this will be the
-	 * past start time of the current scanout. This is meant to adhere
-	 * to the OpenML OML_sync_control extension specification.
-	 *
-	 * \param dev dev DRM device handle.
-	 * \param pipe crtc for which timestamp should be returned.
-	 * \param *max_error Maximum allowable timestamp error in nanoseconds.
-	 *                   Implementation should strive to provide timestamp
-	 *                   with an error of at most *max_error nanoseconds.
-	 *                   Returns true upper bound on error for timestamp.
-	 * \param *vblank_time Target location for returned vblank timestamp.
-	 * \param flags 0 = Defaults, no special treatment needed.
-	 * \param       DRM_CALLED_FROM_VBLIRQ = Function is called from vblank
-	 *	        irq handler. Some drivers need to apply some workarounds
-	 *              for gpu-specific vblank irq quirks if flag is set.
-	 *
-	 * \returns
-	 * Zero if timestamping isn't supported in current display mode or a
-	 * negative number on failure. A positive status code on success,
-	 * which describes how the vblank_time timestamp was computed.
-	 */
-	int (*get_vblank_timestamp) (struct drm_device *dev, unsigned int pipe,
-				     int *max_error,
-				     struct timeval *vblank_time,
-				     unsigned flags);
-
-	/* these have to be filled in */
-
-	irqreturn_t(*irq_handler) (DRM_IRQ_ARGS);
-	void (*irq_preinstall) (struct drm_device *dev);
-	int (*irq_postinstall) (struct drm_device *dev);
-	void (*irq_uninstall) (struct drm_device *dev);
-
-#ifdef __NetBSD__
-	int (*request_irq)(struct drm_device *, int);
-	void (*free_irq)(struct drm_device *);
-#endif
-
-	/* Master routines */
-	int (*master_create)(struct drm_device *dev, struct drm_master *master);
-	void (*master_destroy)(struct drm_device *dev, struct drm_master *master);
-	/**
-	 * master_set is called whenever the minor master is set.
-	 * master_drop is called whenever the minor master is dropped.
-	 */
-
-	int (*master_set)(struct drm_device *dev, struct drm_file *file_priv,
-			  bool from_open);
-	void (*master_drop)(struct drm_device *dev, struct drm_file *file_priv,
-			    bool from_release);
-
-	int (*debugfs_init)(struct drm_minor *minor);
-	void (*debugfs_cleanup)(struct drm_minor *minor);
-
-	/**
-	 * Driver-specific constructor for drm_gem_objects, to set up
-	 * obj->driver_private.
-	 *
-	 * Returns 0 on success.
-	 */
-	void (*gem_free_object) (struct drm_gem_object *obj);
-	int (*gem_open_object) (struct drm_gem_object *, struct drm_file *);
-	void (*gem_close_object) (struct drm_gem_object *, struct drm_file *);
-
-	/* prime: */
-	/* export handle -> fd (see drm_gem_prime_handle_to_fd() helper) */
-	int (*prime_handle_to_fd)(struct drm_device *dev, struct drm_file *file_priv,
-				uint32_t handle, uint32_t flags, int *prime_fd);
-	/* import fd -> handle (see drm_gem_prime_fd_to_handle() helper) */
-	int (*prime_fd_to_handle)(struct drm_device *dev, struct drm_file *file_priv,
-				int prime_fd, uint32_t *handle);
-	/* export GEM -> dmabuf */
-	struct dma_buf * (*gem_prime_export)(struct drm_device *dev,
-				struct drm_gem_object *obj, int flags);
-	/* import dmabuf -> GEM */
-	struct drm_gem_object * (*gem_prime_import)(struct drm_device *dev,
-				struct dma_buf *dma_buf);
-	/* low-level interface used by drm_gem_prime_{import,export} */
-	int (*gem_prime_pin)(struct drm_gem_object *obj);
-	void (*gem_prime_unpin)(struct drm_gem_object *obj);
-	struct reservation_object * (*gem_prime_res_obj)(
-				struct drm_gem_object *obj);
-	struct sg_table *(*gem_prime_get_sg_table)(struct drm_gem_object *obj);
-	struct drm_gem_object *(*gem_prime_import_sg_table)(
-				struct drm_device *dev,
-				struct dma_buf_attachment *attach,
-				struct sg_table *sgt);
-	void *(*gem_prime_vmap)(struct drm_gem_object *obj);
-	void (*gem_prime_vunmap)(struct drm_gem_object *obj, void *vaddr);
-#ifdef __NetBSD__
-	int (*gem_prime_mmap)(struct drm_gem_object *obj, off_t *offp,
-	    size_t len, int prot, int *flagsp, int *advicep,
-	    struct uvm_object **uobjp, int *maxprotp);
-#else
-	int (*gem_prime_mmap)(struct drm_gem_object *obj,
-				struct vm_area_struct *vma);
-#endif
-
-	/* vga arb irq handler */
-	void (*vgaarb_irq)(struct drm_device *dev, bool state);
-
-	/* dumb alloc support */
-	int (*dumb_create)(struct drm_file *file_priv,
-			   struct drm_device *dev,
-			   struct drm_mode_create_dumb *args);
-	int (*dumb_map_offset)(struct drm_file *file_priv,
-			       struct drm_device *dev, uint32_t handle,
-			       uint64_t *offset);
-	int (*dumb_destroy)(struct drm_file *file_priv,
-			    struct drm_device *dev,
-			    uint32_t handle);
-
-	/* Driver private ops for this object */
-#ifdef __NetBSD__
-	int (*mmap_object)(struct drm_device *, off_t, size_t, int,
-	    struct uvm_object **, voff_t *, struct file *);
-	const struct uvm_pagerops *gem_uvm_ops;
-#else
-	const struct vm_operations_struct *gem_vm_ops;
-#endif
-
-	int major;
-	int minor;
-	int patchlevel;
-	const char *name;
-	const char *desc;
-	const char *date;
-
-	u32 driver_features;
-	int dev_priv_size;
-	const struct drm_ioctl_desc *ioctls;
-	int num_ioctls;
-	const struct file_operations *fops;
-
-#ifdef __NetBSD__
-	int (*ioctl_override)(struct file *, unsigned long, void *);
-#endif
-
-	/* List of devices hanging off this driver with stealth attach. */
-	struct list_head legacy_dev_list;
-};
-
 enum drm_minor_type {
 	DRM_MINOR_LEGACY,
 	DRM_MINOR_CONTROL,
@@ -598,38 +316,6 @@ struct drm_minor {
 };
 
 
-struct drm_pending_vblank_event {
-	struct drm_pending_event base;
-	unsigned int pipe;
-	struct drm_event_vblank event;
-};
-
-struct drm_vblank_crtc {
-	struct drm_device *dev;		/* pointer to the drm_device */
-#ifdef __NetBSD__
-	drm_waitqueue_t queue;
-#else
-	wait_queue_head_t queue;	/**< VBLANK wait queue */
-#endif
-	struct timer_list disable_timer;		/* delayed disable timer */
-
-	/* vblank counter, protected by dev->vblank_time_lock for writes */
-	u32 count;
-	/* vblank timestamps, protected by dev->vblank_time_lock for writes */
-	struct timeval time[DRM_VBLANKTIME_RBSIZE];
-
-	atomic_t refcount;		/* number of users of vblank interruptsper crtc */
-	u32 last;			/* protected by dev->vbl_lock, used */
-					/* for wraparound handling */
-	u32 last_wait;			/* Last vblank seqno waited per CRTC */
-	unsigned int inmodeset;		/* Display driver is setting mode */
-	unsigned int pipe;		/* crtc index */
-	int framedur_ns;		/* frame/field duration in ns */
-	int linedur_ns;			/* line duration in ns */
-	bool enabled;			/* so we don't call enable more than
-					   once per disable */
-};
-
 #define DRM_SWITCH_POWER_ON 0
 #define DRM_SWITCH_POWER_OFF 1
 #define DRM_SWITCH_POWER_CHANGING 2
@@ -696,71 +382,6 @@ extern int drm_irq_install(struct drm_de
 #endif
 extern int drm_irq_uninstall(struct drm_device *dev);
 
-extern int drm_vblank_init(struct drm_device *dev, unsigned int num_crtcs);
-extern int drm_wait_vblank(struct drm_device *dev, void *data,
-			   struct drm_file *filp);
-extern u32 drm_vblank_count(struct drm_device *dev, unsigned int pipe);
-extern u32 drm_crtc_vblank_count(struct drm_crtc *crtc);
-extern u32 drm_vblank_count_and_time(struct drm_device *dev, unsigned int pipe,
-				     struct timeval *vblanktime);
-extern u32 drm_crtc_vblank_count_and_time(struct drm_crtc *crtc,
-					  struct timeval *vblanktime);
-extern void drm_send_vblank_event(struct drm_device *dev, unsigned int pipe,
-				  struct drm_pending_vblank_event *e);
-extern void drm_crtc_send_vblank_event(struct drm_crtc *crtc,
-				       struct drm_pending_vblank_event *e);
-extern void drm_arm_vblank_event(struct drm_device *dev, unsigned int pipe,
-				 struct drm_pending_vblank_event *e);
-extern void drm_crtc_arm_vblank_event(struct drm_crtc *crtc,
-				      struct drm_pending_vblank_event *e);
-extern bool drm_handle_vblank(struct drm_device *dev, unsigned int pipe);
-extern bool drm_crtc_handle_vblank(struct drm_crtc *crtc);
-extern int drm_vblank_get(struct drm_device *dev, unsigned int pipe);
-extern void drm_vblank_put(struct drm_device *dev, unsigned int pipe);
-extern int drm_crtc_vblank_get(struct drm_crtc *crtc);
-extern void drm_crtc_vblank_put(struct drm_crtc *crtc);
-extern int drm_vblank_get_locked(struct drm_device *dev, unsigned int pipe);
-extern void drm_vblank_put_locked(struct drm_device *dev, unsigned int pipe);
-extern int drm_crtc_vblank_get_locked(struct drm_crtc *crtc);
-extern void drm_crtc_vblank_put_locked(struct drm_crtc *crtc);
-extern void drm_wait_one_vblank(struct drm_device *dev, unsigned int pipe);
-extern void drm_crtc_wait_one_vblank(struct drm_crtc *crtc);
-extern void drm_vblank_off(struct drm_device *dev, unsigned int pipe);
-extern void drm_vblank_on(struct drm_device *dev, unsigned int pipe);
-extern void drm_crtc_vblank_off(struct drm_crtc *crtc);
-extern void drm_crtc_vblank_reset(struct drm_crtc *crtc);
-extern void drm_crtc_vblank_on(struct drm_crtc *crtc);
-extern void drm_vblank_cleanup(struct drm_device *dev);
-extern u32 drm_vblank_no_hw_counter(struct drm_device *dev, unsigned int pipe);
-
-extern int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev,
-						 unsigned int pipe, int *max_error,
-						 struct timeval *vblank_time,
-						 unsigned flags,
-						 const struct drm_display_mode *mode);
-extern void drm_calc_timestamping_constants(struct drm_crtc *crtc,
-					    const struct drm_display_mode *mode);
-
-/**
- * drm_crtc_vblank_waitqueue - get vblank waitqueue for the CRTC
- * @crtc: which CRTC's vblank waitqueue to retrieve
- *
- * This function returns a pointer to the vblank waitqueue for the CRTC.
- * Drivers can use this to implement vblank waits using wait_event() & co.
- */
-#ifdef __NetBSD__
-static inline drm_waitqueue_t *drm_crtc_vblank_waitqueue(struct drm_crtc *crtc)
-#else
-static inline wait_queue_head_t *drm_crtc_vblank_waitqueue(struct drm_crtc *crtc)
-#endif
-{
-	return &crtc->dev->vblank[drm_crtc_index(crtc)].queue;
-}
-
-/* Modesetting support */
-extern void drm_vblank_pre_modeset(struct drm_device *dev, unsigned int pipe);
-extern void drm_vblank_post_modeset(struct drm_device *dev, unsigned int pipe);
-
 				/* Stub support (drm_stub.h) */
 extern struct drm_master *drm_master_get(struct drm_master *master);
 extern void drm_master_put(struct drm_master **master);

Index: src/sys/external/bsd/drm2/dist/include/drm/drm_drv.h
diff -u src/sys/external/bsd/drm2/dist/include/drm/drm_drv.h:1.3 src/sys/external/bsd/drm2/dist/include/drm/drm_drv.h:1.4
--- src/sys/external/bsd/drm2/dist/include/drm/drm_drv.h:1.3	Sun Dec 19 00:46:08 2021
+++ src/sys/external/bsd/drm2/dist/include/drm/drm_drv.h	Sun Dec 19 01:56:33 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: drm_drv.h,v 1.3 2021/12/19 00:46:08 riastradh Exp $	*/
+/*	$NetBSD: drm_drv.h,v 1.4 2021/12/19 01:56:33 riastradh Exp $	*/
 
 /*
  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
@@ -461,6 +461,11 @@ struct drm_driver {
 	 */
 	void (*irq_uninstall) (struct drm_device *dev);
 
+#ifdef __NetBSD__
+	int (*request_irq)(struct drm_device *, int);
+	void (*free_irq)(struct drm_device *);
+#endif
+
 	/**
 	 * @master_create:
 	 *
@@ -654,8 +659,14 @@ struct drm_driver {
 	 * FIXME: There's way too much duplication going on here, and also moved
 	 * to &drm_gem_object_funcs.
 	 */
+#ifdef __NetBSD__
+	int (*gem_prime_mmap)(struct drm_gem_object *obj, off_t *offp,
+	    size_t len, int prot, int *flagsp, int *advicep,
+	    struct uvm_object **uobjp, int *maxprotp);
+#else
 	int (*gem_prime_mmap)(struct drm_gem_object *obj,
 				struct vm_area_struct *vma);
+#endif
 
 	/**
 	 * @dumb_create:
@@ -725,7 +736,13 @@ struct drm_driver {
 	 * For GEM drivers this is deprecated in favour of
 	 * &drm_gem_object_funcs.vm_ops.
 	 */
+#ifdef __NetBSD__
+	int (*mmap_object)(struct drm_device *, off_t, size_t, int,
+	    struct uvm_object **, voff_t *, struct file *);
+	const struct uvm_pagerops *gem_uvm_ops;
+#else
 	const struct vm_operations_struct *gem_vm_ops;
+#endif
 
 	/** @major: driver major number */
 	int major;
@@ -769,6 +786,10 @@ struct drm_driver {
 	 */
 	const struct file_operations *fops;
 
+#ifdef __NetBSD__
+	int (*ioctl_override)(struct file *, unsigned long, void *);
+#endif
+
 	/* Everything below here is for legacy driver, never use! */
 	/* private: */
 

Index: src/sys/external/bsd/drm2/dist/include/drm/drm_vblank.h
diff -u src/sys/external/bsd/drm2/dist/include/drm/drm_vblank.h:1.6 src/sys/external/bsd/drm2/dist/include/drm/drm_vblank.h:1.7
--- src/sys/external/bsd/drm2/dist/include/drm/drm_vblank.h:1.6	Sun Dec 19 01:14:36 2021
+++ src/sys/external/bsd/drm2/dist/include/drm/drm_vblank.h	Sun Dec 19 01:56:33 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: drm_vblank.h,v 1.6 2021/12/19 01:14:36 riastradh Exp $	*/
+/*	$NetBSD: drm_vblank.h,v 1.7 2021/12/19 01:56:33 riastradh Exp $	*/
 
 /*
  * Copyright 2016 Intel Corp.
@@ -106,7 +106,11 @@ struct drm_vblank_crtc {
 	/**
 	 * @queue: Wait queue for vblank waiters.
 	 */
+#ifdef __NetBSD__
+	drm_waitqueue_t queue;
+#else
 	wait_queue_head_t queue;
+#endif
 	/**
 	 * @disable_timer: Disable timer for the delayed vblank disabling
 	 * hysteresis logic. Vblank disabling is controlled through the
@@ -247,7 +251,11 @@ bool drm_calc_vbltimestamp_from_scanoutp
 					   bool in_vblank_irq);
 void drm_calc_timestamping_constants(struct drm_crtc *crtc,
 				     const struct drm_display_mode *mode);
+#ifdef __NetBSD__
+drm_waitqueue_t *drm_crtc_vblank_waitqueue(struct drm_crtc *crtc)
+#else
 wait_queue_head_t *drm_crtc_vblank_waitqueue(struct drm_crtc *crtc);
+#endif
 void drm_crtc_set_max_vblank_count(struct drm_crtc *crtc,
 				   u32 max_vblank_count);
 #endif

Reply via email to