Commit | Line | Data |
---|---|---|
705ececd MG |
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 | */ | |
766f9d20 GKH |
45 | int line6_dump_request_async(struct line6_dump_request *l6dr, |
46 | struct usb_line6 *line6, int num) | |
705ececd MG |
47 | { |
48 | int ret; | |
49 | line6_invalidate_current(l6dr); | |
766f9d20 GKH |
50 | ret = line6_send_raw_message_async(line6, l6dr->reqbufs[num].buffer, |
51 | l6dr->reqbufs[num].length); | |
705ececd | 52 | |
766f9d20 | 53 | if (ret < 0) |
705ececd MG |
54 | line6_dump_finished(l6dr); |
55 | ||
56 | return ret; | |
57 | } | |
58 | ||
59 | /* | |
60 | Send an asynchronous dump request after a given interval. | |
61 | */ | |
62 | void line6_startup_delayed(struct line6_dump_request *l6dr, int seconds, | |
766f9d20 | 63 | void (*function)(unsigned long), void *data) |
705ececd MG |
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 | */ | |
74 | int 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 | ||
766f9d20 GKH |
81 | while (l6dr->in_progress) { |
82 | if (nonblock) { | |
705ececd MG |
83 | retval = -EAGAIN; |
84 | break; | |
85 | } | |
86 | ||
766f9d20 | 87 | if (signal_pending(current)) { |
705ececd MG |
88 | retval = -ERESTARTSYS; |
89 | break; | |
766f9d20 | 90 | } else |
705ececd MG |
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 | */ | |
766f9d20 GKH |
102 | int line6_dumpreq_initbuf(struct line6_dump_request *l6dr, const void *buf, |
103 | size_t len, int num) | |
705ececd MG |
104 | { |
105 | l6dr->reqbufs[num].buffer = kmalloc(len, GFP_KERNEL); | |
766f9d20 GKH |
106 | if (l6dr->reqbufs[num].buffer == NULL) |
107 | return -ENOMEM; | |
705ececd MG |
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 | */ | |
766f9d20 GKH |
116 | int line6_dumpreq_init(struct line6_dump_request *l6dr, const void *buf, |
117 | size_t len) | |
705ececd MG |
118 | { |
119 | int ret; | |
120 | ret = line6_dumpreq_initbuf(l6dr, buf, len, 0); | |
766f9d20 GKH |
121 | if (ret < 0) |
122 | return ret; | |
705ececd MG |
123 | init_waitqueue_head(&l6dr->wait); |
124 | init_timer(&l6dr->timer); | |
125 | return 0; | |
126 | } | |
127 | ||
128 | /* | |
129 | Destruct dump request data structure. | |
130 | */ | |
131 | void line6_dumpreq_destructbuf(struct line6_dump_request *l6dr, int num) | |
132 | { | |
766f9d20 GKH |
133 | if (l6dr == NULL) |
134 | return; | |
135 | if (l6dr->reqbufs[num].buffer == NULL) | |
136 | return; | |
705ececd MG |
137 | kfree(l6dr->reqbufs[num].buffer); |
138 | l6dr->reqbufs[num].buffer = NULL; | |
139 | } | |
140 | ||
141 | /* | |
142 | Destruct dump request data structure. | |
143 | */ | |
144 | void line6_dumpreq_destruct(struct line6_dump_request *l6dr) | |
145 | { | |
766f9d20 GKH |
146 | if (l6dr->reqbufs[0].buffer == NULL) |
147 | return; | |
705ececd MG |
148 | line6_dumpreq_destructbuf(l6dr, 0); |
149 | l6dr->ok = 1; | |
150 | del_timer_sync(&l6dr->timer); | |
151 | } |