Module: xenomai-abe
Branch: analogy
Commit: cf02a8150301897faa20cfb3e34b453e35ed083f
URL:    
http://git.xenomai.org/?p=xenomai-abe.git;a=commit;h=cf02a8150301897faa20cfb3e34b453e35ed083f

Author: Alexis Berlemont <alexis.berlem...@gmail.com>
Date:   Tue Feb  9 00:40:51 2010 +0100

analogy: improve robustness of the detach procedure
    
If a subdevice was busy because of an acquisition, the detach
procedure failed and left the device in an incoherent state which
needed reboot. This bug was fixed by adding a pre-cleanup function
which tests subdevices' status.

---

 include/analogy/transfer.h      |    2 +
 ksrc/drivers/analogy/device.c   |   13 ++++++---
 ksrc/drivers/analogy/transfer.c |   53 ++++++++++++++++++++++++++++++--------
 3 files changed, 52 insertions(+), 16 deletions(-)

diff --git a/include/analogy/transfer.h b/include/analogy/transfer.h
index e50d574..3d44ac6 100644
--- a/include/analogy/transfer.h
+++ b/include/analogy/transfer.h
@@ -33,6 +33,7 @@
 #define A4L_TSF_BUSY 0
 #define A4L_TSF_BULK 1
 #define A4L_TSF_MMAP 2
+#define A4L_TSF_CLEAN 3
 
 /* Fields init values */
 #define A4L_IRQ_UNUSED (unsigned int)((unsigned short)(~0))
@@ -81,6 +82,7 @@ int a4l_rdproc_transfer(char *page,
 
 void a4l_presetup_transfer(a4l_cxt_t * cxt);
 int a4l_setup_transfer(a4l_cxt_t * cxt);
+int a4l_precleanup_transfer(a4l_cxt_t * cxt);
 int a4l_cleanup_transfer(a4l_cxt_t * cxt);
 int a4l_reserve_transfer(a4l_cxt_t * cxt, int idx_subd);
 int a4l_init_transfer(a4l_cxt_t * cxt, a4l_cmd_t * cmd);
diff --git a/ksrc/drivers/analogy/device.c b/ksrc/drivers/analogy/device.c
index 1b7a012..cd586f7 100644
--- a/ksrc/drivers/analogy/device.c
+++ b/ksrc/drivers/analogy/device.c
@@ -432,18 +432,21 @@ int a4l_ioctl_devcfg(a4l_cxt_t * cxt, void *arg)
 
        if (arg == NULL) {
                /* Basic checking */
-               if (!test_bit
-                   (A4L_DEV_ATTACHED, &(a4l_get_dev(cxt)->flags))) {
+               if (!test_bit(A4L_DEV_ATTACHED, &(a4l_get_dev(cxt)->flags))) {
                        __a4l_err("a4l_ioctl_devcfg: "
                                  "free device, no driver to detach\n");
                        return -EINVAL;
                }
-               /* Removes the related proc file */
+               /* Pre-cleanup of the transfer structure, we ensure
+                  that nothing is busy */
+               if ((ret = a4l_precleanup_transfer(cxt)) != 0)
+                       return ret;
+               /* Remove the related proc file */
                a4l_proc_detach(cxt);
-               /* Frees the transfer structure and its related data */
+               /* Free the transfer structure and its related data */
                if ((ret = a4l_cleanup_transfer(cxt)) != 0)
                        return ret;
-               /* Frees the device and the driver from each other */
+               /* Free the device and the driver from each other */
                if ((ret = a4l_device_detach(cxt)) == 0)
                        clear_bit(A4L_DEV_ATTACHED,
                                  &(a4l_get_dev(cxt)->flags));
diff --git a/ksrc/drivers/analogy/transfer.c b/ksrc/drivers/analogy/transfer.c
index b2c91bd..5239d08 100644
--- a/ksrc/drivers/analogy/transfer.c
+++ b/ksrc/drivers/analogy/transfer.c
@@ -33,39 +33,70 @@
 
 /* --- Initialization / cleanup / cancel functions --- */
 
-int a4l_cleanup_transfer(a4l_cxt_t * cxt)
+int a4l_precleanup_transfer(a4l_cxt_t * cxt)
 {
        a4l_dev_t *dev;
        a4l_trf_t *tsf;
-       int i;
+       int i, err = 0;
 
        __a4l_dbg(1, core_dbg, 
-                 "a4l_cleanup_transfer: minor=%d\n", 
+                 "a4l_precleanup_transfer: minor=%d\n", 
                  a4l_get_minor(cxt));
 
        dev = a4l_get_dev(cxt);
        tsf = &dev->transfer;
 
        if (tsf == NULL) {
-               __a4l_err("a4l_cleanup_transfer: "
+               __a4l_err("a4l_precleanup_transfer: "
                          "incoherent status, transfer block not reachable\n");
                return -ENODEV;
        }
 
        for (i = 0; i < tsf->nb_subd; i++) {
-               if (test_bit(A4L_TSF_BUSY, &(tsf->status[i]))) {
-                       __a4l_err("a4l_cleanup_transfer: "
-                                 "device busy, acquisition occuring\n");
-                       return -EBUSY;
-               }
 
                if (test_bit(A4L_TSF_MMAP, &(tsf->status[i]))) {
-                       __a4l_err("a4l_cleanup_transfer: "
+                       __a4l_err("a4l_precleanup_transfer: "
                                  "device busy, buffer must be unmapped\n");
-                       return -EPERM;
+                       err = -EPERM;
+                       goto out_error;
                }
+
+               if (test_and_set_bit(A4L_TSF_BUSY, &(tsf->status[i]))) {
+                       __a4l_err("a4l_precleanup_transfer: "
+                                 "device busy, acquisition occuring\n");
+                       err = -EBUSY;
+                       goto out_error;
+               } else
+                       set_bit(A4L_TSF_CLEAN, &(tsf->status[i]));
        }
 
+       return 0;
+
+out_error:
+       for (i = 0; i < tsf->nb_subd; i++) {
+
+               if (test_bit(A4L_TSF_CLEAN, &(tsf->status[i]))){
+                       clear_bit(A4L_TSF_BUSY, &(tsf->status[i]));
+                       clear_bit(A4L_TSF_CLEAN, &(tsf->status[i]));
+               }
+       }
+
+       return err;
+}
+
+int a4l_cleanup_transfer(a4l_cxt_t * cxt)
+{
+       a4l_dev_t *dev;
+       a4l_trf_t *tsf;
+       int i;
+
+       __a4l_dbg(1, core_dbg, 
+                 "a4l_cleanup_transfer: minor=%d\n", 
+                 a4l_get_minor(cxt));
+
+       dev = a4l_get_dev(cxt);
+       tsf = &dev->transfer;
+
        /* Releases the various buffers */
        if (tsf->status != NULL)
                rtdm_free(tsf->status);


_______________________________________________
Xenomai-git mailing list
Xenomai-git@gna.org
https://mail.gna.org/listinfo/xenomai-git

Reply via email to