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