Staging: add line6 usb driver
[linux-2.6] / drivers / staging / line6 / dumprequest.c
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 */
19 void 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 */
28 void 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 */
36 void 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 */
45 int line6_dump_request_async(struct line6_dump_request *l6dr, struct usb_line6 *line6, int num)
46 {
47         int ret;
48         line6_invalidate_current(l6dr);
49         ret = line6_send_raw_message_async(line6, l6dr->reqbufs[num].buffer, l6dr->reqbufs[num].length);
50
51         if(ret < 0)
52                 line6_dump_finished(l6dr);
53
54         return ret;
55 }
56
57 /*
58         Send an asynchronous dump request after a given interval.
59 */
60 void line6_startup_delayed(struct line6_dump_request *l6dr, int seconds,
61                                                                                                          void (*function)(unsigned long), void *data)
62 {
63         l6dr->timer.expires = jiffies + seconds * HZ;
64         l6dr->timer.function = function;
65         l6dr->timer.data = (unsigned long)data;
66         add_timer(&l6dr->timer);
67 }
68
69 /*
70         Wait for completion.
71 */
72 int line6_wait_dump(struct line6_dump_request *l6dr, int nonblock)
73 {
74         int retval = 0;
75         DECLARE_WAITQUEUE(wait, current);
76         add_wait_queue(&l6dr->wait, &wait);
77         current->state = TASK_INTERRUPTIBLE;
78
79         while(l6dr->in_progress) {
80                 if(nonblock) {
81                         retval = -EAGAIN;
82                         break;
83                 }
84
85                 if(signal_pending(current)) {
86                         retval = -ERESTARTSYS;
87                         break;
88                 }
89                 else
90                         schedule();
91         }
92
93         current->state = TASK_RUNNING;
94         remove_wait_queue(&l6dr->wait, &wait);
95         return retval;
96 }
97
98 /*
99         Initialize dump request buffer.
100 */
101 int line6_dumpreq_initbuf(struct line6_dump_request *l6dr, const void *buf, size_t len, int num)
102 {
103         l6dr->reqbufs[num].buffer = kmalloc(len, GFP_KERNEL);
104         if(l6dr->reqbufs[num].buffer == NULL) return -ENOMEM;
105         memcpy(l6dr->reqbufs[num].buffer, buf, len);
106         l6dr->reqbufs[num].length = len;
107         return 0;
108 }
109
110 /*
111         Initialize dump request data structure (including one buffer).
112 */
113 int line6_dumpreq_init(struct line6_dump_request *l6dr, const void *buf, size_t len)
114 {
115         int ret;
116         ret = line6_dumpreq_initbuf(l6dr, buf, len, 0);
117         if(ret < 0) return ret;
118         init_waitqueue_head(&l6dr->wait);
119         init_timer(&l6dr->timer);
120         return 0;
121 }
122
123 /*
124         Destruct dump request data structure.
125 */
126 void line6_dumpreq_destructbuf(struct line6_dump_request *l6dr, int num)
127 {
128         if(l6dr == NULL) return;
129         if(l6dr->reqbufs[num].buffer == NULL) return;
130         kfree(l6dr->reqbufs[num].buffer);
131         l6dr->reqbufs[num].buffer = NULL;
132 }
133
134 /*
135         Destruct dump request data structure.
136 */
137 void line6_dumpreq_destruct(struct line6_dump_request *l6dr)
138 {
139         if(l6dr->reqbufs[0].buffer == NULL) return;
140         line6_dumpreq_destructbuf(l6dr, 0);
141         l6dr->ok = 1;
142         del_timer_sync(&l6dr->timer);
143 }