linux/drivers/staging/line6/dumprequest.c
<<
>>
Prefs
   1/*
   2 * Line6 Linux USB driver - 0.8.0
   3 *
   4 * Copyright (C) 2004-2009 Markus Grabner (grabner@icg.tugraz.at)
   5 *
   6 *      This program is free software; you can redistribute it and/or
   7 *      modify it under the terms of the GNU General Public License as
   8 *      published by the Free Software Foundation, version 2.
   9 *
  10 */
  11
  12#include "driver.h"
  13#include "dumprequest.h"
  14
  15
  16/*
  17        Set "dump in progress" flag.
  18*/
  19void line6_dump_started(struct line6_dump_request *l6dr, int dest)
  20{
  21        l6dr->in_progress = dest;
  22}
  23
  24/*
  25        Invalidate current channel, i.e., set "dump in progress" flag.
  26        Reading from the "dump" special file blocks until dump is completed.
  27*/
  28void line6_invalidate_current(struct line6_dump_request *l6dr)
  29{
  30        line6_dump_started(l6dr, LINE6_DUMP_CURRENT);
  31}
  32
  33/*
  34        Clear "dump in progress" flag and notify waiting processes.
  35*/
  36void line6_dump_finished(struct line6_dump_request *l6dr)
  37{
  38        l6dr->in_progress = LINE6_DUMP_NONE;
  39        wake_up_interruptible(&l6dr->wait);
  40}
  41
  42/*
  43        Send an asynchronous channel dump request.
  44*/
  45int line6_dump_request_async(struct line6_dump_request *l6dr,
  46                             struct usb_line6 *line6, int num)
  47{
  48        int ret;
  49        line6_invalidate_current(l6dr);
  50        ret = line6_send_raw_message_async(line6, l6dr->reqbufs[num].buffer,
  51                                           l6dr->reqbufs[num].length);
  52
  53        if (ret < 0)
  54                line6_dump_finished(l6dr);
  55
  56        return ret;
  57}
  58
  59/*
  60        Send an asynchronous dump request after a given interval.
  61*/
  62void line6_startup_delayed(struct line6_dump_request *l6dr, int seconds,
  63                           void (*function)(unsigned long), void *data)
  64{
  65        l6dr->timer.expires = jiffies + seconds * HZ;
  66        l6dr->timer.function = function;
  67        l6dr->timer.data = (unsigned long)data;
  68        add_timer(&l6dr->timer);
  69}
  70
  71/*
  72        Wait for completion.
  73*/
  74int line6_wait_dump(struct line6_dump_request *l6dr, int nonblock)
  75{
  76        int retval = 0;
  77        DECLARE_WAITQUEUE(wait, current);
  78        add_wait_queue(&l6dr->wait, &wait);
  79        current->state = TASK_INTERRUPTIBLE;
  80
  81        while (l6dr->in_progress) {
  82                if (nonblock) {
  83                        retval = -EAGAIN;
  84                        break;
  85                }
  86
  87                if (signal_pending(current)) {
  88                        retval = -ERESTARTSYS;
  89                        break;
  90                } else
  91                        schedule();
  92        }
  93
  94        current->state = TASK_RUNNING;
  95        remove_wait_queue(&l6dr->wait, &wait);
  96        return retval;
  97}
  98
  99/*
 100        Initialize dump request buffer.
 101*/
 102int line6_dumpreq_initbuf(struct line6_dump_request *l6dr, const void *buf,
 103                          size_t len, int num)
 104{
 105        l6dr->reqbufs[num].buffer = kmalloc(len, GFP_KERNEL);
 106        if (l6dr->reqbufs[num].buffer == NULL)
 107                return -ENOMEM;
 108        memcpy(l6dr->reqbufs[num].buffer, buf, len);
 109        l6dr->reqbufs[num].length = len;
 110        return 0;
 111}
 112
 113/*
 114        Initialize dump request data structure (including one buffer).
 115*/
 116int line6_dumpreq_init(struct line6_dump_request *l6dr, const void *buf,
 117                       size_t len)
 118{
 119        int ret;
 120        ret = line6_dumpreq_initbuf(l6dr, buf, len, 0);
 121        if (ret < 0)
 122                return ret;
 123        init_waitqueue_head(&l6dr->wait);
 124        init_timer(&l6dr->timer);
 125        return 0;
 126}
 127
 128/*
 129        Destruct dump request data structure.
 130*/
 131void line6_dumpreq_destructbuf(struct line6_dump_request *l6dr, int num)
 132{
 133        if (l6dr == NULL)
 134                return;
 135        if (l6dr->reqbufs[num].buffer == NULL)
 136                return;
 137        kfree(l6dr->reqbufs[num].buffer);
 138        l6dr->reqbufs[num].buffer = NULL;
 139}
 140
 141/*
 142        Destruct dump request data structure.
 143*/
 144void line6_dumpreq_destruct(struct line6_dump_request *l6dr)
 145{
 146        if (l6dr->reqbufs[0].buffer == NULL)
 147                return;
 148        line6_dumpreq_destructbuf(l6dr, 0);
 149        l6dr->ok = 1;
 150        del_timer_sync(&l6dr->timer);
 151}
 152