1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58#include <linux/usb.h>
59#include <linux/slab.h>
60#include "i2400m-usb.h"
61
62
63#define D_SUBMODULE notif
64#include "usb-debug-levels.h"
65
66
67static const
68__le32 i2400m_ZERO_BARKER[4] = { 0, 0, 0, 0 };
69
70
71
72
73
74
75
76
77
78
79
80
81static
82int i2400mu_notification_grok(struct i2400mu *i2400mu, const void *buf,
83 size_t buf_len)
84{
85 int ret;
86 struct device *dev = &i2400mu->usb_iface->dev;
87 struct i2400m *i2400m = &i2400mu->i2400m;
88
89 d_fnstart(4, dev, "(i2400m %p buf %p buf_len %zu)\n",
90 i2400mu, buf, buf_len);
91 ret = -EIO;
92 if (buf_len < sizeof(i2400m_ZERO_BARKER))
93
94 goto error_bad_size;
95 ret = 0;
96 if (!memcmp(i2400m_ZERO_BARKER, buf, sizeof(i2400m_ZERO_BARKER))) {
97 i2400mu_rx_kick(i2400mu);
98 goto out;
99 }
100 ret = i2400m_is_boot_barker(i2400m, buf, buf_len);
101 if (unlikely(ret >= 0))
102 ret = i2400m_dev_reset_handle(i2400m, "device rebooted");
103 else
104 i2400m_unknown_barker(i2400m, buf, buf_len);
105error_bad_size:
106out:
107 d_fnend(4, dev, "(i2400m %p buf %p buf_len %zu) = %d\n",
108 i2400mu, buf, buf_len, ret);
109 return ret;
110}
111
112
113
114
115
116
117
118
119
120
121
122static
123void i2400mu_notification_cb(struct urb *urb)
124{
125 int ret;
126 struct i2400mu *i2400mu = urb->context;
127 struct device *dev = &i2400mu->usb_iface->dev;
128
129 d_fnstart(4, dev, "(urb %p status %d actual_length %d)\n",
130 urb, urb->status, urb->actual_length);
131 ret = urb->status;
132 switch (ret) {
133 case 0:
134 ret = i2400mu_notification_grok(i2400mu, urb->transfer_buffer,
135 urb->actual_length);
136 if (ret == -EIO && edc_inc(&i2400mu->urb_edc, EDC_MAX_ERRORS,
137 EDC_ERROR_TIMEFRAME))
138 goto error_exceeded;
139 if (ret == -ENOMEM)
140 goto error_exceeded;
141 break;
142 case -EINVAL:
143 case -ENODEV:
144 case -ENOENT:
145 case -ESHUTDOWN:
146 case -ECONNRESET:
147 goto out;
148 default:
149 if (edc_inc(&i2400mu->urb_edc,
150 EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME))
151 goto error_exceeded;
152 dev_err(dev, "notification: URB error %d, retrying\n",
153 urb->status);
154 }
155 usb_mark_last_busy(i2400mu->usb_dev);
156 ret = usb_submit_urb(i2400mu->notif_urb, GFP_ATOMIC);
157 switch (ret) {
158 case 0:
159 case -EINVAL:
160 case -ENODEV:
161 case -ENOENT:
162 case -ESHUTDOWN:
163 case -ECONNRESET:
164 break;
165 default:
166 dev_err(dev, "notification: cannot submit URB: %d\n", ret);
167 goto error_submit;
168 }
169 d_fnend(4, dev, "(urb %p status %d actual_length %d) = void\n",
170 urb, urb->status, urb->actual_length);
171 return;
172
173error_exceeded:
174 dev_err(dev, "maximum errors in notification URB exceeded; "
175 "resetting device\n");
176error_submit:
177 usb_queue_reset_device(i2400mu->usb_iface);
178out:
179 d_fnend(4, dev, "(urb %p status %d actual_length %d) = void\n",
180 urb, urb->status, urb->actual_length);
181}
182
183
184
185
186
187
188
189
190
191
192int i2400mu_notification_setup(struct i2400mu *i2400mu)
193{
194 struct device *dev = &i2400mu->usb_iface->dev;
195 int usb_pipe, ret = 0;
196 struct usb_endpoint_descriptor *epd;
197 char *buf;
198
199 d_fnstart(4, dev, "(i2400m %p)\n", i2400mu);
200 buf = kmalloc(I2400MU_MAX_NOTIFICATION_LEN, GFP_KERNEL | GFP_DMA);
201 if (buf == NULL) {
202 ret = -ENOMEM;
203 goto error_buf_alloc;
204 }
205
206 i2400mu->notif_urb = usb_alloc_urb(0, GFP_KERNEL);
207 if (!i2400mu->notif_urb) {
208 ret = -ENOMEM;
209 goto error_alloc_urb;
210 }
211 epd = usb_get_epd(i2400mu->usb_iface,
212 i2400mu->endpoint_cfg.notification);
213 usb_pipe = usb_rcvintpipe(i2400mu->usb_dev, epd->bEndpointAddress);
214 usb_fill_int_urb(i2400mu->notif_urb, i2400mu->usb_dev, usb_pipe,
215 buf, I2400MU_MAX_NOTIFICATION_LEN,
216 i2400mu_notification_cb, i2400mu, epd->bInterval);
217 ret = usb_submit_urb(i2400mu->notif_urb, GFP_KERNEL);
218 if (ret != 0) {
219 dev_err(dev, "notification: cannot submit URB: %d\n", ret);
220 goto error_submit;
221 }
222 d_fnend(4, dev, "(i2400m %p) = %d\n", i2400mu, ret);
223 return ret;
224
225error_submit:
226 usb_free_urb(i2400mu->notif_urb);
227error_alloc_urb:
228 kfree(buf);
229error_buf_alloc:
230 d_fnend(4, dev, "(i2400m %p) = %d\n", i2400mu, ret);
231 return ret;
232}
233
234
235
236
237
238
239
240
241
242
243
244
245
246void i2400mu_notification_release(struct i2400mu *i2400mu)
247{
248 struct device *dev = &i2400mu->usb_iface->dev;
249
250 d_fnstart(4, dev, "(i2400mu %p)\n", i2400mu);
251 if (i2400mu->notif_urb != NULL) {
252 usb_kill_urb(i2400mu->notif_urb);
253 kfree(i2400mu->notif_urb->transfer_buffer);
254 usb_free_urb(i2400mu->notif_urb);
255 i2400mu->notif_urb = NULL;
256 }
257 d_fnend(4, dev, "(i2400mu %p)\n", i2400mu);
258}
259