Module Name: src
Committed By: skrll
Date: Sun Feb 28 09:16:20 UTC 2016
Modified Files:
src/sys/dev/usb [nick-nhusb]: ehci.c ohci.c uhci.c usbdi.c xhci.c
src/sys/external/bsd/dwc2 [nick-nhusb]: dwc2.c
Log Message:
Centralise the up_repeat handling and use the standard pipe method to
start the next transfer. This allows the removal of a bunch of code
in the upm_done methods for interrupt transfers which had copies of
the upm_start method code.
At the same time we can perform the upm_done method before calling the
transfer callback allowing correct bus_dma(9) operations before
using the transfer DMA buffer.
To generate a diff of this commit:
cvs rdiff -u -r1.234.2.90 -r1.234.2.91 src/sys/dev/usb/ehci.c
cvs rdiff -u -r1.254.2.53 -r1.254.2.54 src/sys/dev/usb/ohci.c
cvs rdiff -u -r1.264.4.62 -r1.264.4.63 src/sys/dev/usb/uhci.c
cvs rdiff -u -r1.162.2.42 -r1.162.2.43 src/sys/dev/usb/usbdi.c
cvs rdiff -u -r1.28.2.52 -r1.28.2.53 src/sys/dev/usb/xhci.c
cvs rdiff -u -r1.32.2.17 -r1.32.2.18 src/sys/external/bsd/dwc2/dwc2.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/dev/usb/ehci.c
diff -u src/sys/dev/usb/ehci.c:1.234.2.90 src/sys/dev/usb/ehci.c:1.234.2.91
--- src/sys/dev/usb/ehci.c:1.234.2.90 Sat Feb 27 17:03:58 2016
+++ src/sys/dev/usb/ehci.c Sun Feb 28 09:16:20 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: ehci.c,v 1.234.2.90 2016/02/27 17:03:58 skrll Exp $ */
+/* $NetBSD: ehci.c,v 1.234.2.91 2016/02/28 09:16:20 skrll Exp $ */
/*
* Copyright (c) 2004-2012 The NetBSD Foundation, Inc.
@@ -53,7 +53,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ehci.c,v 1.234.2.90 2016/02/27 17:03:58 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ehci.c,v 1.234.2.91 2016/02/28 09:16:20 skrll Exp $");
#include "ohci.h"
#include "uhci.h"
@@ -838,11 +838,6 @@ ehci_softintr(void *v)
* the _SAFE version of TAILQ_FOREACH.
*/
TAILQ_FOREACH_SAFE(ex, &cq, ex_next, nextex) {
- /*
- * XXX transfer_complete memcpys out transfer data (for in
- * endpoints) during this call, before methods->done is called.
- * A dma sync required beforehand.
- */
usb_transfer_complete(&ex->ex_xfer);
}
@@ -4248,11 +4243,9 @@ ehci_device_intr_close(struct usbd_pipe
Static void
ehci_device_intr_done(struct usbd_xfer *xfer)
{
- ehci_softc_t *sc = EHCI_XFER2SC(xfer);
- struct ehci_xfer *exfer = EHCI_XFER2EXFER(xfer);
+ ehci_softc_t *sc __diagused = EHCI_XFER2SC(xfer);
struct ehci_pipe *epipe = EHCI_XFER2EPIPE(xfer);
- ehci_soft_qh_t *sqh;
- int len, isread, endpt;
+ int isread, endpt;
USBHIST_FUNC(); USBHIST_CALLED(ehcidebug);
@@ -4261,43 +4254,10 @@ ehci_device_intr_done(struct usbd_xfer *
KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
- if (xfer->ux_pipe->up_repeat) {
-
- KASSERT(exfer->ex_isdone);
-#ifdef DIAGNOSTIC
- exfer->ex_isdone = false;
-#endif
-
- len = xfer->ux_length;
- endpt = epipe->pipe.up_endpoint->ue_edesc->bEndpointAddress;
- isread = UE_GET_DIR(endpt) == UE_DIR_IN;
- usb_syncmem(&xfer->ux_dmabuf, 0, len,
- isread ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
- sqh = epipe->sqh;
-
- ehci_soft_qtd_t *end;
- ehci_reset_sqtd_chain(sc, xfer, len, isread,
- &epipe->nexttoggle, &end);
- end->qtd.qtd_status |= htole32(EHCI_QTD_IOC);
- usb_syncmem(&end->dma, end->offs, sizeof(end->qtd),
- BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
-
- exfer->ex_sqtdend = end;
-
- /* also does usb_syncmem(sqh) */
- ehci_set_qh_qtd(sqh, exfer->ex_sqtdstart);
- if (xfer->ux_timeout && !sc->sc_bus.ub_usepolling) {
- callout_reset(&xfer->ux_callout,
- mstohz(xfer->ux_timeout), ehci_timeout, xfer);
- }
- ehci_add_intr_list(sc, exfer);
- xfer->ux_status = USBD_IN_PROGRESS;
- } else {
- endpt = epipe->pipe.up_endpoint->ue_edesc->bEndpointAddress;
- isread = UE_GET_DIR(endpt) == UE_DIR_IN;
- usb_syncmem(&xfer->ux_dmabuf, 0, xfer->ux_length,
- isread ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
- }
+ endpt = epipe->pipe.up_endpoint->ue_edesc->bEndpointAddress;
+ isread = UE_GET_DIR(endpt) == UE_DIR_IN;
+ usb_syncmem(&xfer->ux_dmabuf, 0, xfer->ux_length,
+ isread ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
}
/************************/
Index: src/sys/dev/usb/ohci.c
diff -u src/sys/dev/usb/ohci.c:1.254.2.53 src/sys/dev/usb/ohci.c:1.254.2.54
--- src/sys/dev/usb/ohci.c:1.254.2.53 Sat Feb 27 15:54:30 2016
+++ src/sys/dev/usb/ohci.c Sun Feb 28 09:16:20 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: ohci.c,v 1.254.2.53 2016/02/27 15:54:30 skrll Exp $ */
+/* $NetBSD: ohci.c,v 1.254.2.54 2016/02/28 09:16:20 skrll Exp $ */
/*
* Copyright (c) 1998, 2004, 2005, 2012 The NetBSD Foundation, Inc.
@@ -41,7 +41,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ohci.c,v 1.254.2.53 2016/02/27 15:54:30 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ohci.c,v 1.254.2.54 2016/02/28 09:16:20 skrll Exp $");
#include "opt_usb.h"
@@ -1679,10 +1679,7 @@ ohci_device_ctrl_done(struct usbd_xfer *
void
ohci_device_intr_done(struct usbd_xfer *xfer)
{
- struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer);
- struct ohci_pipe *opipe = OHCI_PIPE2OPIPE(xfer->ux_pipe);
- ohci_softc_t *sc = OHCI_XFER2SC(xfer);
- ohci_soft_ed_t *sed = opipe->sed;
+ ohci_softc_t *sc __diagused = OHCI_XFER2SC(xfer);
int isread =
(UE_GET_DIR(xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress) == UE_DIR_IN);
@@ -1693,47 +1690,6 @@ ohci_device_intr_done(struct usbd_xfer *
usb_syncmem(&xfer->ux_dmabuf, 0, xfer->ux_length,
isread ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
- if (xfer->ux_pipe->up_repeat) {
- ohci_soft_td_t *data, *last, *tail;
- int len = xfer->ux_length;
-
- /*
- * Use the pipe "tail" TD as our first and loan our first TD
- * to the next transfer.
- */
- data = opipe->tail.td;
- opipe->tail.td = ox->ox_stds[0];
- ox->ox_stds[0] = data;
- ohci_reset_std_chain(sc, xfer, len, isread, data, &last);
-
- /* point at sentinel */
- tail = opipe->tail.td;
- memset(&tail->td, 0, sizeof(tail->td));
- tail->nexttd = NULL;
- tail->xfer = NULL;
- usb_syncmem(&tail->dma, tail->offs, sizeof(tail->td),
- BUS_DMASYNC_PREWRITE);
-
- /* We want interrupt at the end of the transfer. */
- last->td.td_flags &= HTOO32(~OHCI_TD_INTR_MASK);
- last->td.td_flags |= HTOO32(OHCI_TD_SET_DI(1));
-
- last->td.td_nexttd = HTOO32(tail->physaddr);
- last->nexttd = tail;
- last->flags |= OHCI_CALL_DONE;
- usb_syncmem(&last->dma, last->offs, sizeof(last->td),
- BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
-
- xfer->ux_hcpriv = data;
- xfer->ux_actlen = 0;
-
- /* Insert ED in schedule */
- sed->ed.ed_tailp = HTOO32(tail->physaddr);
- usb_syncmem(&sed->dma,
- sed->offs + offsetof(ohci_ed_t, ed_tailp),
- sizeof(sed->ed.ed_tailp),
- BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
- }
}
void
@@ -1803,6 +1759,12 @@ ohci_rhsc(ohci_softc_t *sc, struct usbd_
void
ohci_root_intr_done(struct usbd_xfer *xfer)
{
+ ohci_softc_t *sc = OHCI_XFER2SC(xfer);
+
+ KASSERT(mutex_owned(&sc->sc_lock));
+
+ KASSERT(sc->sc_intrxfer == xfer);
+ sc->sc_intrxfer = NULL;
}
/*
Index: src/sys/dev/usb/uhci.c
diff -u src/sys/dev/usb/uhci.c:1.264.4.62 src/sys/dev/usb/uhci.c:1.264.4.63
--- src/sys/dev/usb/uhci.c:1.264.4.62 Sat Feb 27 16:07:01 2016
+++ src/sys/dev/usb/uhci.c Sun Feb 28 09:16:20 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: uhci.c,v 1.264.4.62 2016/02/27 16:07:01 skrll Exp $ */
+/* $NetBSD: uhci.c,v 1.264.4.63 2016/02/28 09:16:20 skrll Exp $ */
/*
* Copyright (c) 1998, 2004, 2011, 2012 The NetBSD Foundation, Inc.
@@ -42,7 +42,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uhci.c,v 1.264.4.62 2016/02/27 16:07:01 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uhci.c,v 1.264.4.63 2016/02/28 09:16:20 skrll Exp $");
#include "opt_usb.h"
@@ -3399,7 +3399,6 @@ void
uhci_device_intr_done(struct usbd_xfer *xfer)
{
uhci_softc_t *sc = UHCI_XFER2SC(xfer);
- struct uhci_xfer *ux = UHCI_XFER2UXFER(xfer);
struct uhci_pipe *upipe = UHCI_PIPE2UPIPE(xfer->ux_pipe);
uhci_soft_qh_t *sqh;
int i, npoll;
@@ -3419,49 +3418,10 @@ uhci_device_intr_done(struct usbd_xfer *
sizeof(sqh->qh.qh_elink),
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
}
-
- if (xfer->ux_pipe->up_repeat) {
- uhci_soft_td_t *data, *dataend;
- int endpt = upipe->pipe.up_endpoint->ue_edesc->bEndpointAddress;
- int isread = UE_GET_DIR(endpt) == UE_DIR_IN;
-
- KASSERT(ux->ux_isdone);
-#ifdef DIAGNOSTIC
- ux->ux_isdone = false;
-#endif
- DPRINTFN(5, "re-queueing", 0, 0, 0, 0);
-
- data = ux->ux_stdstart;
- uhci_reset_std_chain(sc, xfer, xfer->ux_length, isread,
- &upipe->nexttoggle, &dataend);
- dataend->td.td_status |= htole32(UHCI_TD_IOC);
- usb_syncmem(&dataend->dma,
- dataend->offs + offsetof(uhci_td_t, td_status),
- sizeof(dataend->td.td_status),
- BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
-
-#ifdef UHCI_DEBUG
- if (uhcidebug >= 10) {
- DPRINTF("--- dump start ---", 0, 0, 0, 0);
- uhci_dump_tds(data);
- uhci_dump_qh(upipe->intr.qhs[0]);
- DPRINTF("--- dump end ---", 0, 0, 0, 0);
- }
-#endif
-
- ux->ux_stdend = dataend;
- for (i = 0; i < npoll; i++) {
- sqh = upipe->intr.qhs[i];
- sqh->elink = data;
- sqh->qh.qh_elink = htole32(data->physaddr | UHCI_PTR_TD);
- usb_syncmem(&sqh->dma,
- sqh->offs + offsetof(uhci_qh_t, qh_elink),
- sizeof(sqh->qh.qh_elink),
- BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
- }
- xfer->ux_status = USBD_IN_PROGRESS;
- uhci_add_intr_list(sc, ux);
- }
+ const int endpt = upipe->pipe.up_endpoint->ue_edesc->bEndpointAddress;
+ const bool isread = UE_GET_DIR(endpt) == UE_DIR_IN;
+ usb_syncmem(&xfer->ux_dmabuf, 0, xfer->ux_length,
+ isread ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
}
/* Deallocate request data structures */
Index: src/sys/dev/usb/usbdi.c
diff -u src/sys/dev/usb/usbdi.c:1.162.2.42 src/sys/dev/usb/usbdi.c:1.162.2.43
--- src/sys/dev/usb/usbdi.c:1.162.2.42 Sun Feb 7 15:50:43 2016
+++ src/sys/dev/usb/usbdi.c Sun Feb 28 09:16:20 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: usbdi.c,v 1.162.2.42 2016/02/07 15:50:43 skrll Exp $ */
+/* $NetBSD: usbdi.c,v 1.162.2.43 2016/02/28 09:16:20 skrll Exp $ */
/*
* Copyright (c) 1998, 2012, 2015 The NetBSD Foundation, Inc.
@@ -32,7 +32,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: usbdi.c,v 1.162.2.42 2016/02/07 15:50:43 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: usbdi.c,v 1.162.2.43 2016/02/28 09:16:20 skrll Exp $");
#ifdef _KERNEL_OPT
#include "opt_usb.h"
@@ -893,10 +893,11 @@ usb_transfer_complete(struct usbd_xfer *
struct usbd_pipe *pipe = xfer->ux_pipe;
struct usbd_bus *bus = pipe->up_dev->ud_bus;
int sync = xfer->ux_flags & USBD_SYNCHRONOUS;
- int erred = xfer->ux_status == USBD_CANCELLED ||
+ int erred =
+ xfer->ux_status == USBD_CANCELLED ||
xfer->ux_status == USBD_TIMEOUT;
int polling = bus->ub_usepolling;
- int repeat;
+ int repeat = pipe->up_repeat;
USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
@@ -907,21 +908,10 @@ usb_transfer_complete(struct usbd_xfer *
KASSERT(xfer->ux_state == XFER_ONQU);
KASSERT(pipe != NULL);
- repeat = pipe->up_repeat;
/* XXXX */
if (polling)
pipe->up_running = 0;
- if (xfer->ux_length != 0 && xfer->ux_buffer != xfer->ux_buf) {
- KDASSERTMSG(xfer->ux_actlen <= xfer->ux_length,
- "actlen %d length %d",xfer->ux_actlen, xfer->ux_length);
-
- /* Only if IN transfer */
- if (usbd_xfer_isread(xfer)) {
- memcpy(xfer->ux_buffer, xfer->ux_buf, xfer->ux_actlen);
- }
- }
-
if (!repeat) {
/* Remove request from queue. */
@@ -952,58 +942,54 @@ usb_transfer_complete(struct usbd_xfer *
xfer->ux_status = USBD_SHORT_XFER;
}
- if (repeat) {
- USBHIST_LOG(usbdebug, "xfer %p doing callback %p status %x",
- xfer, xfer->ux_callback, xfer->ux_status, 0);
- if (xfer->ux_callback) {
- if (!polling)
- mutex_exit(pipe->up_dev->ud_bus->ub_lock);
-
- if (!(pipe->up_flags & USBD_MPSAFE))
- KERNEL_LOCK(1, curlwp);
- xfer->ux_callback(xfer, xfer->ux_priv, xfer->ux_status);
- USBHIST_LOG(usbdebug, "xfer %p doing done %p", xfer,
- pipe->up_methods->upm_done, 0, 0);
- if (!(pipe->up_flags & USBD_MPSAFE))
- KERNEL_UNLOCK_ONE(curlwp);
+ USBHIST_LOG(usbdebug, "xfer %p doing done %p", xfer,
+ pipe->up_methods->upm_done, 0, 0);
+ pipe->up_methods->upm_done(xfer);
- if (!polling)
- mutex_enter(pipe->up_dev->ud_bus->ub_lock);
- }
- pipe->up_methods->upm_done(xfer);
- } else {
- USBHIST_LOG(usbdebug, "xfer %p doing done %p", xfer,
- pipe->up_methods->upm_done, 0, 0);
- pipe->up_methods->upm_done(xfer);
- USBHIST_LOG(usbdebug, "xfer %p doing callback %p status %x",
- xfer, xfer->ux_callback, xfer->ux_status, 0);
- if (xfer->ux_callback) {
- if (!polling)
- mutex_exit(pipe->up_dev->ud_bus->ub_lock);
-
- if (!(pipe->up_flags & USBD_MPSAFE))
- KERNEL_LOCK(1, curlwp);
- xfer->ux_callback(xfer, xfer->ux_priv, xfer->ux_status);
- if (!(pipe->up_flags & USBD_MPSAFE))
- KERNEL_UNLOCK_ONE(curlwp);
+ if (xfer->ux_length != 0 && xfer->ux_buffer != xfer->ux_buf) {
+ KDASSERTMSG(xfer->ux_actlen <= xfer->ux_length,
+ "actlen %d length %d",xfer->ux_actlen, xfer->ux_length);
- if (!polling)
- mutex_enter(pipe->up_dev->ud_bus->ub_lock);
+ /* Only if IN transfer */
+ if (usbd_xfer_isread(xfer)) {
+ memcpy(xfer->ux_buffer, xfer->ux_buf, xfer->ux_actlen);
}
}
+ USBHIST_LOG(usbdebug, "xfer %p doing callback %p status %d",
+ xfer, xfer->ux_callback, xfer->ux_status, 0);
+
+ if (xfer->ux_callback) {
+ if (!polling)
+ mutex_exit(pipe->up_dev->ud_bus->ub_lock);
+
+ if (!(pipe->up_flags & USBD_MPSAFE))
+ KERNEL_LOCK(1, curlwp);
+
+ xfer->ux_callback(xfer, xfer->ux_priv, xfer->ux_status);
+
+ if (!(pipe->up_flags & USBD_MPSAFE))
+ KERNEL_UNLOCK_ONE(curlwp);
+
+ if (!polling)
+ mutex_enter(pipe->up_dev->ud_bus->ub_lock);
+ }
+
if (sync && !polling) {
USBHIST_LOG(usbdebug, "<- done xfer %p, wakeup", xfer, 0, 0, 0);
cv_broadcast(&xfer->ux_cv);
}
- if (!repeat) {
+ if (repeat) {
+ xfer->ux_actlen = 0;
+ xfer->ux_status = USBD_NOT_STARTED;
+ } else {
/* XXX should we stop the queue on all errors? */
if (erred && pipe->up_iface != NULL) /* not control pipe */
pipe->up_running = 0;
- else
- usbd_start_next(pipe);
}
+ if (pipe->up_running)
+ usbd_start_next(pipe);
}
/* Called with USB lock held. */
Index: src/sys/dev/usb/xhci.c
diff -u src/sys/dev/usb/xhci.c:1.28.2.52 src/sys/dev/usb/xhci.c:1.28.2.53
--- src/sys/dev/usb/xhci.c:1.28.2.52 Sat Feb 13 09:33:12 2016
+++ src/sys/dev/usb/xhci.c Sun Feb 28 09:16:20 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: xhci.c,v 1.28.2.52 2016/02/13 09:33:12 skrll Exp $ */
+/* $NetBSD: xhci.c,v 1.28.2.53 2016/02/28 09:16:20 skrll Exp $ */
/*
* Copyright (c) 2013 Jonathan A. Kollasch
@@ -36,7 +36,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: xhci.c,v 1.28.2.52 2016/02/13 09:33:12 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: xhci.c,v 1.28.2.53 2016/02/28 09:16:20 skrll Exp $");
#include "opt_usb.h"
@@ -3264,7 +3264,13 @@ static void
xhci_device_ctrl_done(struct usbd_xfer *xfer)
{
XHCIHIST_FUNC(); XHCIHIST_CALLED();
-
+ usb_device_request_t *req = &xfer->ux_request;
+ int len = UGETW(req->wLength);
+ int rd = req->bmRequestType & UT_READ;
+
+ if (len)
+ usb_syncmem(&xfer->ux_dmabuf, 0, len,
+ rd ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
}
static void
@@ -3512,9 +3518,6 @@ xhci_device_intr_done(struct usbd_xfer *
printf("\n");
#endif
- if (xfer->ux_pipe->up_repeat) {
- xfer->ux_status = xhci_device_intr_start(xfer);
- }
}
static void
Index: src/sys/external/bsd/dwc2/dwc2.c
diff -u src/sys/external/bsd/dwc2/dwc2.c:1.32.2.17 src/sys/external/bsd/dwc2/dwc2.c:1.32.2.18
--- src/sys/external/bsd/dwc2/dwc2.c:1.32.2.17 Sun Dec 27 12:10:03 2015
+++ src/sys/external/bsd/dwc2/dwc2.c Sun Feb 28 09:16:20 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: dwc2.c,v 1.32.2.17 2015/12/27 12:10:03 skrll Exp $ */
+/* $NetBSD: dwc2.c,v 1.32.2.18 2016/02/28 09:16:20 skrll Exp $ */
/*-
* Copyright (c) 2013 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: dwc2.c,v 1.32.2.17 2015/12/27 12:10:03 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: dwc2.c,v 1.32.2.18 2016/02/28 09:16:20 skrll Exp $");
#include "opt_usb.h"
@@ -911,11 +911,6 @@ dwc2_device_intr_done(struct usbd_xfer *
{
DPRINTF("\n");
-
- if (xfer->ux_pipe->up_repeat) {
- xfer->ux_status = USBD_IN_PROGRESS;
- dwc2_device_start(xfer);
- }
}
/***********************************************************************/