linux-old/drivers/usb/auerchain.c
<<
>>
Prefs
   1/*****************************************************************************/
   2/*
   3 *      auerchain.c  --  Auerswald PBX/System Telephone chained urb support.
   4 *
   5 *      Copyright (C) 2002  Wolfgang Mües (wolfgang@iksw-muees.de)
   6 *
   7 *      This program is free software; you can redistribute it and/or modify
   8 *      it under the terms of the GNU General Public License as published by
   9 *      the Free Software Foundation; either version 2 of the License, or
  10 *      (at your option) any later version.
  11 *
  12 *      This program is distributed in the hope that it will be useful,
  13 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 *      GNU General Public License for more details.
  16 *
  17 *      You should have received a copy of the GNU General Public License
  18 *      along with this program; if not, write to the Free Software
  19 *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20 */
  21 /*****************************************************************************/
  22
  23#undef DEBUG                    /* include debug macros until it's done */
  24#include <linux/usb.h>
  25#include "auerchain.h"
  26#include <linux/slab.h>
  27
  28/* completion function for chained urbs */
  29static void auerchain_complete(struct urb *urb)
  30{
  31        unsigned long flags;
  32        int result;
  33
  34        /* get pointer to element and to chain */
  35        struct auerchainelement *acep =
  36            (struct auerchainelement *) urb->context;
  37        struct auerchain *acp = acep->chain;
  38
  39        /* restore original entries in urb */
  40        urb->context = acep->context;
  41        urb->complete = acep->complete;
  42
  43        dbg("auerchain_complete called");
  44
  45        /* call original completion function
  46           NOTE: this function may lead to more urbs submitted into the chain.
  47           (no chain lock at calling complete()!)
  48           acp->active != NULL is protecting us against recursion. */
  49        urb->complete(urb);
  50
  51        /* detach element from chain data structure */
  52        spin_lock_irqsave(&acp->lock, flags);
  53        if (acp->active != acep)        /* paranoia debug check */
  54                dbg("auerchain_complete: completion on non-active element called!");
  55        else
  56                acp->active = NULL;
  57
  58        /* add the used chain element to the list of free elements */
  59        list_add_tail(&acep->list, &acp->free_list);
  60        acep = NULL;
  61
  62        /* is there a new element waiting in the chain? */
  63        if (!acp->active && !list_empty(&acp->waiting_list)) {
  64                /* yes: get the entry */
  65                struct list_head *tmp = acp->waiting_list.next;
  66                list_del(tmp);
  67                acep = list_entry(tmp, struct auerchainelement, list);
  68                acp->active = acep;
  69        }
  70        spin_unlock_irqrestore(&acp->lock, flags);
  71
  72        /* submit the new urb */
  73        if (acep) {
  74                urb = acep->urbp;
  75                dbg("auerchain_complete: submitting next urb from chain");
  76                urb->status = 0;        /* needed! */
  77                result = usb_submit_urb(urb);
  78
  79                /* check for submit errors */
  80                if (result) {
  81                        urb->status = result;
  82                        dbg("auerchain_complete: usb_submit_urb with error code %d", result);
  83                        /* and do error handling via *this* completion function (recursive) */
  84                        auerchain_complete(urb);
  85                }
  86        } else {
  87                /* simple return without submitting a new urb.
  88                   The empty chain is detected with acp->active == NULL. */
  89        };
  90}
  91
  92/* submit function for chained urbs
  93   this function may be called from completion context or from user space!
  94   early = 1 -> submit in front of chain
  95*/
  96int auerchain_submit_urb_list(struct auerchain *acp, struct urb *urb,
  97                              int early)
  98{
  99        int result;
 100        unsigned long flags;
 101        struct auerchainelement *acep = NULL;
 102
 103        dbg("auerchain_submit_urb called");
 104
 105        /* try to get a chain element */
 106        spin_lock_irqsave(&acp->lock, flags);
 107        if (!list_empty(&acp->free_list)) {
 108                /* yes: get the entry */
 109                struct list_head *tmp = acp->free_list.next;
 110                list_del(tmp);
 111                acep = list_entry(tmp, struct auerchainelement, list);
 112        }
 113        spin_unlock_irqrestore(&acp->lock, flags);
 114
 115        /* if no chain element available: return with error */
 116        if (!acep) {
 117                return -ENOMEM;
 118        }
 119
 120        /* fill in the new chain element values */
 121        acep->chain = acp;
 122        acep->context = urb->context;
 123        acep->complete = urb->complete;
 124        acep->urbp = urb;
 125        INIT_LIST_HEAD(&acep->list);
 126
 127        /* modify urb */
 128        urb->context = acep;
 129        urb->complete = auerchain_complete;
 130        urb->status = -EINPROGRESS;     /* usb_submit_urb does this, too */
 131
 132        /* add element to chain - or start it immediately */
 133        spin_lock_irqsave(&acp->lock, flags);
 134        if (acp->active) {
 135                /* there is traffic in the chain, simple add element to chain */
 136                if (early) {
 137                        dbg("adding new urb to head of chain");
 138                        list_add(&acep->list, &acp->waiting_list);
 139                } else {
 140                        dbg("adding new urb to end of chain");
 141                        list_add_tail(&acep->list, &acp->waiting_list);
 142                }
 143                acep = NULL;
 144        } else {
 145                /* the chain is empty. Prepare restart */
 146                acp->active = acep;
 147        }
 148        /* Spin has to be removed before usb_submit_urb! */
 149        spin_unlock_irqrestore(&acp->lock, flags);
 150
 151        /* Submit urb if immediate restart */
 152        if (acep) {
 153                dbg("submitting urb immediate");
 154                urb->status = 0;        /* needed! */
 155                result = usb_submit_urb(urb);
 156                /* check for submit errors */
 157                if (result) {
 158                        urb->status = result;
 159                        dbg("auerchain_submit_urb: usb_submit_urb with error code %d", result);
 160                        /* and do error handling via completion function */
 161                        auerchain_complete(urb);
 162                }
 163        }
 164
 165        return 0;
 166}
 167
 168/* submit function for chained urbs
 169   this function may be called from completion context or from user space!
 170*/
 171int auerchain_submit_urb(struct auerchain *acp, struct urb *urb)
 172{
 173        return auerchain_submit_urb_list(acp, urb, 0);
 174}
 175
 176/* cancel an urb which is submitted to the chain
 177   the result is 0 if the urb is cancelled, or -EINPROGRESS if
 178   USB_ASYNC_UNLINK is set and the function is successfully started.
 179*/
 180int auerchain_unlink_urb(struct auerchain *acp, struct urb *urb)
 181{
 182        unsigned long flags;
 183        struct urb *urbp;
 184        struct auerchainelement *acep;
 185        struct list_head *tmp;
 186
 187        dbg("auerchain_unlink_urb called");
 188
 189        /* search the chain of waiting elements */
 190        spin_lock_irqsave(&acp->lock, flags);
 191        list_for_each(tmp, &acp->waiting_list) {
 192                acep = list_entry(tmp, struct auerchainelement, list);
 193                if (acep->urbp == urb) {
 194                        list_del(tmp);
 195                        urb->context = acep->context;
 196                        urb->complete = acep->complete;
 197                        list_add_tail(&acep->list, &acp->free_list);
 198                        spin_unlock_irqrestore(&acp->lock, flags);
 199                        dbg("unlink waiting urb");
 200                        urb->status = -ENOENT;
 201                        urb->complete(urb);
 202                        return 0;
 203                }
 204        }
 205        /* not found. */
 206        spin_unlock_irqrestore(&acp->lock, flags);
 207
 208        /* get the active urb */
 209        acep = acp->active;
 210        if (acep) {
 211                urbp = acep->urbp;
 212
 213                /* check if we have to cancel the active urb */
 214                if (urbp == urb) {
 215                        /* note that there is a race condition between the check above
 216                           and the unlink() call because of no lock. This race is harmless,
 217                           because the usb module will detect the unlink() after completion.
 218                           We can't use the acp->lock here because the completion function
 219                           wants to grab it.
 220                         */
 221                        dbg("unlink active urb");
 222                        return usb_unlink_urb(urbp);
 223                }
 224        }
 225
 226        /* not found anyway
 227           ... is some kind of success
 228         */
 229        dbg("urb to unlink not found in chain");
 230        return 0;
 231}
 232
 233/* cancel all urbs which are in the chain.
 234   this function must not be called from interrupt or completion handler.
 235*/
 236void auerchain_unlink_all(struct auerchain *acp)
 237{
 238        unsigned long flags;
 239        struct urb *urbp;
 240        struct auerchainelement *acep;
 241
 242        dbg("auerchain_unlink_all called");
 243
 244        /* clear the chain of waiting elements */
 245        spin_lock_irqsave(&acp->lock, flags);
 246        while (!list_empty(&acp->waiting_list)) {
 247                /* get the next entry */
 248                struct list_head *tmp = acp->waiting_list.next;
 249                list_del(tmp);
 250                acep = list_entry(tmp, struct auerchainelement, list);
 251                urbp = acep->urbp;
 252                urbp->context = acep->context;
 253                urbp->complete = acep->complete;
 254                list_add_tail(&acep->list, &acp->free_list);
 255                spin_unlock_irqrestore(&acp->lock, flags);
 256                dbg("unlink waiting urb");
 257                urbp->status = -ENOENT;
 258                urbp->complete(urbp);
 259                spin_lock_irqsave(&acp->lock, flags);
 260        }
 261        spin_unlock_irqrestore(&acp->lock, flags);
 262
 263        /* clear the active urb */
 264        acep = acp->active;
 265        if (acep) {
 266                urbp = acep->urbp;
 267                urbp->transfer_flags &= ~USB_ASYNC_UNLINK;
 268                dbg("unlink active urb");
 269                usb_unlink_urb(urbp);
 270        }
 271}
 272
 273
 274/* free the chain.
 275   this function must not be called from interrupt or completion handler.
 276*/
 277void auerchain_free(struct auerchain *acp)
 278{
 279        unsigned long flags;
 280        struct auerchainelement *acep;
 281
 282        dbg("auerchain_free called");
 283
 284        /* first, cancel all pending urbs */
 285        auerchain_unlink_all(acp);
 286
 287        /* free the elements */
 288        spin_lock_irqsave(&acp->lock, flags);
 289        while (!list_empty(&acp->free_list)) {
 290                /* get the next entry */
 291                struct list_head *tmp = acp->free_list.next;
 292                list_del(tmp);
 293                spin_unlock_irqrestore(&acp->lock, flags);
 294                acep = list_entry(tmp, struct auerchainelement, list);
 295                kfree(acep);
 296                spin_lock_irqsave(&acp->lock, flags);
 297        }
 298        spin_unlock_irqrestore(&acp->lock, flags);
 299}
 300
 301
 302/* Init the chain control structure */
 303void auerchain_init(struct auerchain *acp)
 304{
 305        /* init the chain data structure */
 306        acp->active = NULL;
 307        spin_lock_init(&acp->lock);
 308        INIT_LIST_HEAD(&acp->waiting_list);
 309        INIT_LIST_HEAD(&acp->free_list);
 310}
 311
 312/* setup a chain.
 313   It is assumed that there is no concurrency while setting up the chain
 314   requirement: auerchain_init()
 315*/
 316int auerchain_setup(struct auerchain *acp, unsigned int numElements)
 317{
 318        struct auerchainelement *acep;
 319
 320        dbg("auerchain_setup called with %d elements", numElements);
 321
 322        /* fill the list of free elements */
 323        for (; numElements; numElements--) {
 324                acep =
 325                    (struct auerchainelement *)
 326                    kmalloc(sizeof(struct auerchainelement), GFP_KERNEL);
 327                if (!acep)
 328                        goto ac_fail;
 329                memset(acep, 0, sizeof(struct auerchainelement));
 330                INIT_LIST_HEAD(&acep->list);
 331                list_add_tail(&acep->list, &acp->free_list);
 332        }
 333        return 0;
 334
 335      ac_fail:  /* free the elements */
 336        while (!list_empty(&acp->free_list)) {
 337                /* get the next entry */
 338                struct list_head *tmp = acp->free_list.next;
 339                list_del(tmp);
 340                acep = list_entry(tmp, struct auerchainelement, list);
 341                kfree(acep);
 342        }
 343        return -ENOMEM;
 344}
 345
 346
 347/* completion handler for synchronous chained URBs */
 348static void auerchain_blocking_completion(struct urb *urb)
 349{
 350        struct auerchain_chs *pchs = (struct auerchain_chs *) urb->context;
 351        pchs->done = 1;
 352        wmb();
 353        wake_up(&pchs->wqh);
 354}
 355
 356
 357/* Starts chained urb and waits for completion or timeout */
 358static int auerchain_start_wait_urb(struct auerchain *acp, struct urb *urb,
 359                                    int timeout, int *actual_length)
 360{
 361        DECLARE_WAITQUEUE(wait, current);
 362        struct auerchain_chs chs;
 363        int status;
 364
 365        dbg("auerchain_start_wait_urb called");
 366        init_waitqueue_head(&chs.wqh);
 367        chs.done = 0;
 368
 369        set_current_state(TASK_UNINTERRUPTIBLE);
 370        add_wait_queue(&chs.wqh, &wait);
 371        urb->context = &chs;
 372        status = auerchain_submit_urb(acp, urb);
 373        if (status) {
 374                /* something went wrong */
 375                set_current_state(TASK_RUNNING);
 376                remove_wait_queue(&chs.wqh, &wait);
 377                return status;
 378        }
 379
 380        while (timeout && !chs.done) {
 381                timeout = schedule_timeout(timeout);
 382                set_current_state(TASK_UNINTERRUPTIBLE);
 383                rmb();
 384        }
 385
 386        set_current_state(TASK_RUNNING);
 387        remove_wait_queue(&chs.wqh, &wait);
 388
 389        if (!timeout && !chs.done) {
 390                if (urb->status != -EINPROGRESS) {      /* No callback?!! */
 391                        dbg("auerchain_start_wait_urb: raced timeout");
 392                        status = urb->status;
 393                } else {
 394                        dbg("auerchain_start_wait_urb: timeout");
 395                        auerchain_unlink_urb(acp, urb); /* remove urb safely */
 396                        status = -ETIMEDOUT;
 397                }
 398        } else
 399                status = urb->status;
 400
 401        if (actual_length)
 402                *actual_length = urb->actual_length;
 403
 404        return status;
 405}
 406
 407
 408/* auerchain_control_msg - Builds a control urb, sends it off and waits for completion
 409   acp: pointer to the auerchain
 410   dev: pointer to the usb device to send the message to
 411   pipe: endpoint "pipe" to send the message to
 412   request: USB message request value
 413   requesttype: USB message request type value
 414   value: USB message value
 415   index: USB message index value
 416   data: pointer to the data to send
 417   size: length in bytes of the data to send
 418   timeout: time to wait for the message to complete before timing out (if 0 the wait is forever)
 419
 420   This function sends a simple control message to a specified endpoint
 421   and waits for the message to complete, or timeout.
 422
 423   If successful, it returns the transfered length, othwise a negative error number.
 424
 425   Don't use this function from within an interrupt context, like a
 426   bottom half handler.  If you need a asyncronous message, or need to send
 427   a message from within interrupt context, use auerchain_submit_urb()
 428*/
 429int auerchain_control_msg(struct auerchain *acp, struct usb_device *dev,
 430                          unsigned int pipe, __u8 request,
 431                          __u8 requesttype, __u16 value, __u16 index,
 432                          void *data, __u16 size, int timeout)
 433{
 434        int ret;
 435        struct usb_ctrlrequest *dr;
 436        struct urb *urb;
 437        int length;
 438
 439        dbg("auerchain_control_msg");
 440        dr = (struct usb_ctrlrequest *)
 441            kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
 442        if (!dr)
 443                return -ENOMEM;
 444        urb = usb_alloc_urb(0);
 445        if (!urb) {
 446                kfree(dr);
 447                return -ENOMEM;
 448        }
 449
 450        dr->bRequestType = requesttype;
 451        dr->bRequest = request;
 452        dr->wValue = cpu_to_le16(value);
 453        dr->wIndex = cpu_to_le16(index);
 454        dr->wLength = cpu_to_le16(size);
 455
 456        FILL_CONTROL_URB(urb, dev, pipe, (unsigned char *) dr, data, size,      /* build urb */
 457                         (usb_complete_t) auerchain_blocking_completion,
 458                         0);
 459        ret = auerchain_start_wait_urb(acp, urb, timeout, &length);
 460
 461        usb_free_urb(urb);
 462        kfree(dr);
 463
 464        if (ret < 0)
 465                return ret;
 466        else
 467                return length;
 468}
 469
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.