diff options
-rw-r--r-- | drivers/staging/ozwpan/ozappif.h | 46 | ||||
-rw-r--r-- | drivers/staging/ozwpan/ozcdev.c | 524 | ||||
-rw-r--r-- | drivers/staging/ozwpan/ozcdev.h | 18 |
3 files changed, 588 insertions, 0 deletions
diff --git a/drivers/staging/ozwpan/ozappif.h b/drivers/staging/ozwpan/ozappif.h new file mode 100644 index 00000000000..af027329387 --- /dev/null +++ b/drivers/staging/ozwpan/ozappif.h | |||
@@ -0,0 +1,46 @@ | |||
1 | /* ----------------------------------------------------------------------------- | ||
2 | * Copyright (c) 2011 Ozmo Inc | ||
3 | * Released under the GNU General Public License Version 2 (GPLv2). | ||
4 | * ----------------------------------------------------------------------------- | ||
5 | */ | ||
6 | #ifndef _OZAPPIF_H | ||
7 | #define _OZAPPIF_H | ||
8 | |||
9 | #include "ozeventdef.h" | ||
10 | |||
11 | #define OZ_IOCTL_MAGIC 0xf4 | ||
12 | |||
13 | struct oz_mac_addr { | ||
14 | unsigned char a[6]; | ||
15 | }; | ||
16 | |||
17 | #define OZ_MAX_PDS 8 | ||
18 | |||
19 | struct oz_pd_list { | ||
20 | int count; | ||
21 | struct oz_mac_addr addr[OZ_MAX_PDS]; | ||
22 | }; | ||
23 | |||
24 | #define OZ_MAX_BINDING_LEN 32 | ||
25 | |||
26 | struct oz_binding_info { | ||
27 | char name[OZ_MAX_BINDING_LEN]; | ||
28 | }; | ||
29 | |||
30 | struct oz_test { | ||
31 | int action; | ||
32 | }; | ||
33 | |||
34 | #define OZ_IOCTL_GET_PD_LIST _IOR(OZ_IOCTL_MAGIC, 0, struct oz_pd_list) | ||
35 | #define OZ_IOCTL_SET_ACTIVE_PD _IOW(OZ_IOCTL_MAGIC, 1, struct oz_mac_addr) | ||
36 | #define OZ_IOCTL_GET_ACTIVE_PD _IOR(OZ_IOCTL_MAGIC, 2, struct oz_mac_addr) | ||
37 | #define OZ_IOCTL_CLEAR_EVENTS _IO(OZ_IOCTL_MAGIC, 3) | ||
38 | #define OZ_IOCTL_GET_EVENTS _IOR(OZ_IOCTL_MAGIC, 4, struct oz_evtlist) | ||
39 | #define OZ_IOCTL_ADD_BINDING _IOW(OZ_IOCTL_MAGIC, 5, struct oz_binding_info) | ||
40 | #define OZ_IOCTL_TEST _IOWR(OZ_IOCTL_MAGIC, 6, struct oz_test) | ||
41 | #define OZ_IOCTL_SET_EVENT_MASK _IOW(OZ_IOCTL_MAGIC, 7, unsigned long) | ||
42 | #define OZ_IOCTL_REMOVE_BINDING _IOW(OZ_IOCTL_MAGIC, 8, struct oz_binding_info) | ||
43 | #define OZ_IOCTL_MAX 9 | ||
44 | |||
45 | |||
46 | #endif /* _OZAPPIF_H */ | ||
diff --git a/drivers/staging/ozwpan/ozcdev.c b/drivers/staging/ozwpan/ozcdev.c new file mode 100644 index 00000000000..912c964cb55 --- /dev/null +++ b/drivers/staging/ozwpan/ozcdev.c | |||
@@ -0,0 +1,524 @@ | |||
1 | /* ----------------------------------------------------------------------------- | ||
2 | * Copyright (c) 2011 Ozmo Inc | ||
3 | * Released under the GNU General Public License Version 2 (GPLv2). | ||
4 | * ----------------------------------------------------------------------------- | ||
5 | */ | ||
6 | #include <linux/module.h> | ||
7 | #include <linux/fs.h> | ||
8 | #include <linux/cdev.h> | ||
9 | #include <linux/uaccess.h> | ||
10 | #include <linux/netdevice.h> | ||
11 | #include <linux/poll.h> | ||
12 | #include <linux/sched.h> | ||
13 | #include "ozconfig.h" | ||
14 | #include "ozprotocol.h" | ||
15 | #include "oztrace.h" | ||
16 | #include "ozappif.h" | ||
17 | #include "ozeltbuf.h" | ||
18 | #include "ozpd.h" | ||
19 | #include "ozproto.h" | ||
20 | #include "ozalloc.h" | ||
21 | #include "ozevent.h" | ||
22 | /*------------------------------------------------------------------------------ | ||
23 | */ | ||
24 | #define OZ_RD_BUF_SZ 256 | ||
25 | struct oz_cdev { | ||
26 | dev_t devnum; | ||
27 | struct cdev cdev; | ||
28 | wait_queue_head_t rdq; | ||
29 | spinlock_t lock; | ||
30 | u8 active_addr[ETH_ALEN]; | ||
31 | struct oz_pd *active_pd; | ||
32 | }; | ||
33 | |||
34 | /* Per PD context for the serial service stored in the PD. */ | ||
35 | struct oz_serial_ctx { | ||
36 | atomic_t ref_count; | ||
37 | u8 tx_seq_num; | ||
38 | u8 rx_seq_num; | ||
39 | u8 rd_buf[OZ_RD_BUF_SZ]; | ||
40 | int rd_in; | ||
41 | int rd_out; | ||
42 | }; | ||
43 | /*------------------------------------------------------------------------------ | ||
44 | */ | ||
45 | int g_taction; | ||
46 | /*------------------------------------------------------------------------------ | ||
47 | */ | ||
48 | static struct oz_cdev g_cdev; | ||
49 | /*------------------------------------------------------------------------------ | ||
50 | * Context: process and softirq | ||
51 | */ | ||
52 | static struct oz_serial_ctx *oz_cdev_claim_ctx(struct oz_pd *pd) | ||
53 | { | ||
54 | struct oz_serial_ctx *ctx; | ||
55 | spin_lock_bh(&pd->app_lock[OZ_APPID_SERIAL-1]); | ||
56 | ctx = (struct oz_serial_ctx *)pd->app_ctx[OZ_APPID_SERIAL-1]; | ||
57 | if (ctx) | ||
58 | atomic_inc(&ctx->ref_count); | ||
59 | spin_unlock_bh(&pd->app_lock[OZ_APPID_SERIAL-1]); | ||
60 | return ctx; | ||
61 | } | ||
62 | /*------------------------------------------------------------------------------ | ||
63 | * Context: softirq or process | ||
64 | */ | ||
65 | static void oz_cdev_release_ctx(struct oz_serial_ctx *ctx) | ||
66 | { | ||
67 | if (atomic_dec_and_test(&ctx->ref_count)) { | ||
68 | oz_trace("Dealloc serial context.\n"); | ||
69 | oz_free(ctx); | ||
70 | } | ||
71 | } | ||
72 | /*------------------------------------------------------------------------------ | ||
73 | * Context: process | ||
74 | */ | ||
75 | int oz_cdev_open(struct inode *inode, struct file *filp) | ||
76 | { | ||
77 | struct oz_cdev *dev; | ||
78 | oz_trace("oz_cdev_open()\n"); | ||
79 | oz_trace("major = %d minor = %d\n", imajor(inode), iminor(inode)); | ||
80 | dev = container_of(inode->i_cdev, struct oz_cdev, cdev); | ||
81 | filp->private_data = dev; | ||
82 | return 0; | ||
83 | } | ||
84 | /*------------------------------------------------------------------------------ | ||
85 | * Context: process | ||
86 | */ | ||
87 | int oz_cdev_release(struct inode *inode, struct file *filp) | ||
88 | { | ||
89 | oz_trace("oz_cdev_release()\n"); | ||
90 | return 0; | ||
91 | } | ||
92 | /*------------------------------------------------------------------------------ | ||
93 | * Context: process | ||
94 | */ | ||
95 | ssize_t oz_cdev_read(struct file *filp, char __user *buf, size_t count, | ||
96 | loff_t *fpos) | ||
97 | { | ||
98 | int n; | ||
99 | int ix; | ||
100 | |||
101 | struct oz_pd *pd; | ||
102 | struct oz_serial_ctx *ctx = 0; | ||
103 | |||
104 | spin_lock_bh(&g_cdev.lock); | ||
105 | pd = g_cdev.active_pd; | ||
106 | if (pd) | ||
107 | oz_pd_get(pd); | ||
108 | spin_unlock_bh(&g_cdev.lock); | ||
109 | if (pd == 0) | ||
110 | return -1; | ||
111 | ctx = oz_cdev_claim_ctx(pd); | ||
112 | if (ctx == 0) | ||
113 | goto out2; | ||
114 | n = ctx->rd_in - ctx->rd_out; | ||
115 | if (n < 0) | ||
116 | n += OZ_RD_BUF_SZ; | ||
117 | if (count > n) | ||
118 | count = n; | ||
119 | ix = ctx->rd_out; | ||
120 | n = OZ_RD_BUF_SZ - ix; | ||
121 | if (n > count) | ||
122 | n = count; | ||
123 | if (copy_to_user(buf, &ctx->rd_buf[ix], n)) { | ||
124 | count = 0; | ||
125 | goto out1; | ||
126 | } | ||
127 | ix += n; | ||
128 | if (ix == OZ_RD_BUF_SZ) | ||
129 | ix = 0; | ||
130 | if (n < count) { | ||
131 | if (copy_to_user(&buf[n], ctx->rd_buf, count-n)) { | ||
132 | count = 0; | ||
133 | goto out1; | ||
134 | } | ||
135 | ix = count-n; | ||
136 | } | ||
137 | ctx->rd_out = ix; | ||
138 | out1: | ||
139 | oz_cdev_release_ctx(ctx); | ||
140 | out2: | ||
141 | oz_pd_put(pd); | ||
142 | return count; | ||
143 | } | ||
144 | /*------------------------------------------------------------------------------ | ||
145 | * Context: process | ||
146 | */ | ||
147 | ssize_t oz_cdev_write(struct file *filp, const char __user *buf, size_t count, | ||
148 | loff_t *fpos) | ||
149 | { | ||
150 | struct oz_pd *pd; | ||
151 | struct oz_elt_buf *eb; | ||
152 | struct oz_elt_info *ei = 0; | ||
153 | struct oz_elt *elt; | ||
154 | struct oz_app_hdr *app_hdr; | ||
155 | struct oz_serial_ctx *ctx; | ||
156 | |||
157 | spin_lock_bh(&g_cdev.lock); | ||
158 | pd = g_cdev.active_pd; | ||
159 | if (pd) | ||
160 | oz_pd_get(pd); | ||
161 | spin_unlock_bh(&g_cdev.lock); | ||
162 | if (pd == 0) | ||
163 | return -1; | ||
164 | eb = &pd->elt_buff; | ||
165 | ei = oz_elt_info_alloc(eb); | ||
166 | if (ei == 0) { | ||
167 | count = 0; | ||
168 | goto out; | ||
169 | } | ||
170 | elt = (struct oz_elt *)ei->data; | ||
171 | app_hdr = (struct oz_app_hdr *)(elt+1); | ||
172 | elt->length = sizeof(struct oz_app_hdr) + count; | ||
173 | elt->type = OZ_ELT_APP_DATA; | ||
174 | ei->app_id = OZ_APPID_SERIAL; | ||
175 | ei->length = elt->length + sizeof(struct oz_elt); | ||
176 | app_hdr->app_id = OZ_APPID_SERIAL; | ||
177 | if (copy_from_user(app_hdr+1, buf, count)) | ||
178 | goto out; | ||
179 | spin_lock_bh(&pd->app_lock[OZ_APPID_USB-1]); | ||
180 | ctx = (struct oz_serial_ctx *)pd->app_ctx[OZ_APPID_SERIAL-1]; | ||
181 | if (ctx) { | ||
182 | app_hdr->elt_seq_num = ctx->tx_seq_num++; | ||
183 | if (ctx->tx_seq_num == 0) | ||
184 | ctx->tx_seq_num = 1; | ||
185 | spin_lock(&eb->lock); | ||
186 | if (oz_queue_elt_info(eb, 0, 0, ei) == 0) | ||
187 | ei = 0; | ||
188 | spin_unlock(&eb->lock); | ||
189 | } | ||
190 | spin_unlock_bh(&pd->app_lock[OZ_APPID_USB-1]); | ||
191 | out: | ||
192 | if (ei) { | ||
193 | count = 0; | ||
194 | spin_lock_bh(&eb->lock); | ||
195 | oz_elt_info_free(eb, ei); | ||
196 | spin_unlock_bh(&eb->lock); | ||
197 | } | ||
198 | oz_pd_put(pd); | ||
199 | return count; | ||
200 | } | ||
201 | /*------------------------------------------------------------------------------ | ||
202 | * Context: process | ||
203 | */ | ||
204 | static int oz_set_active_pd(u8 *addr) | ||
205 | { | ||
206 | int rc = 0; | ||
207 | struct oz_pd *pd; | ||
208 | struct oz_pd *old_pd; | ||
209 | pd = oz_pd_find(addr); | ||
210 | if (pd) { | ||
211 | spin_lock_bh(&g_cdev.lock); | ||
212 | memcpy(g_cdev.active_addr, addr, ETH_ALEN); | ||
213 | old_pd = g_cdev.active_pd; | ||
214 | g_cdev.active_pd = pd; | ||
215 | spin_unlock_bh(&g_cdev.lock); | ||
216 | if (old_pd) | ||
217 | oz_pd_put(old_pd); | ||
218 | } else { | ||
219 | if (!memcmp(addr, "\0\0\0\0\0\0", sizeof(addr))) { | ||
220 | spin_lock_bh(&g_cdev.lock); | ||
221 | pd = g_cdev.active_pd; | ||
222 | g_cdev.active_pd = 0; | ||
223 | memset(g_cdev.active_addr, 0, | ||
224 | sizeof(g_cdev.active_addr)); | ||
225 | spin_unlock_bh(&g_cdev.lock); | ||
226 | if (pd) | ||
227 | oz_pd_put(pd); | ||
228 | } else { | ||
229 | rc = -1; | ||
230 | } | ||
231 | } | ||
232 | return rc; | ||
233 | } | ||
234 | /*------------------------------------------------------------------------------ | ||
235 | * Context: process | ||
236 | */ | ||
237 | long oz_cdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | ||
238 | { | ||
239 | int rc = 0; | ||
240 | if (_IOC_TYPE(cmd) != OZ_IOCTL_MAGIC) | ||
241 | return -ENOTTY; | ||
242 | if (_IOC_NR(cmd) > OZ_IOCTL_MAX) | ||
243 | return -ENOTTY; | ||
244 | if (_IOC_DIR(cmd) & _IOC_READ) | ||
245 | rc = !access_ok(VERIFY_WRITE, (void __user *)arg, | ||
246 | _IOC_SIZE(cmd)); | ||
247 | else if (_IOC_DIR(cmd) & _IOC_WRITE) | ||
248 | rc = !access_ok(VERIFY_READ, (void __user *)arg, | ||
249 | _IOC_SIZE(cmd)); | ||
250 | if (rc) | ||
251 | return -EFAULT; | ||
252 | switch (cmd) { | ||
253 | case OZ_IOCTL_GET_PD_LIST: { | ||
254 | struct oz_pd_list list; | ||
255 | oz_trace("OZ_IOCTL_GET_PD_LIST\n"); | ||
256 | list.count = oz_get_pd_list(list.addr, OZ_MAX_PDS); | ||
257 | if (copy_to_user((void __user *)arg, &list, | ||
258 | sizeof(list))) | ||
259 | return -EFAULT; | ||
260 | } | ||
261 | break; | ||
262 | case OZ_IOCTL_SET_ACTIVE_PD: { | ||
263 | u8 addr[ETH_ALEN]; | ||
264 | oz_trace("OZ_IOCTL_SET_ACTIVE_PD\n"); | ||
265 | if (copy_from_user(addr, (void __user *)arg, ETH_ALEN)) | ||
266 | return -EFAULT; | ||
267 | rc = oz_set_active_pd(addr); | ||
268 | } | ||
269 | break; | ||
270 | case OZ_IOCTL_GET_ACTIVE_PD: { | ||
271 | u8 addr[ETH_ALEN]; | ||
272 | oz_trace("OZ_IOCTL_GET_ACTIVE_PD\n"); | ||
273 | spin_lock_bh(&g_cdev.lock); | ||
274 | memcpy(addr, g_cdev.active_addr, ETH_ALEN); | ||
275 | spin_unlock_bh(&g_cdev.lock); | ||
276 | if (copy_to_user((void __user *)arg, addr, ETH_ALEN)) | ||
277 | return -EFAULT; | ||
278 | } | ||
279 | break; | ||
280 | #ifdef WANT_EVENT_TRACE | ||
281 | case OZ_IOCTL_CLEAR_EVENTS: | ||
282 | oz_events_clear(); | ||
283 | break; | ||
284 | case OZ_IOCTL_GET_EVENTS: | ||
285 | rc = oz_events_copy((void __user *)arg); | ||
286 | break; | ||
287 | case OZ_IOCTL_SET_EVENT_MASK: | ||
288 | if (copy_from_user(&g_evt_mask, (void __user *)arg, | ||
289 | sizeof(unsigned long))) { | ||
290 | return -EFAULT; | ||
291 | } | ||
292 | break; | ||
293 | #endif /* WANT_EVENT_TRACE */ | ||
294 | case OZ_IOCTL_ADD_BINDING: | ||
295 | case OZ_IOCTL_REMOVE_BINDING: { | ||
296 | struct oz_binding_info b; | ||
297 | if (copy_from_user(&b, (void __user *)arg, | ||
298 | sizeof(struct oz_binding_info))) { | ||
299 | return -EFAULT; | ||
300 | } | ||
301 | /* Make sure name is null terminated. */ | ||
302 | b.name[OZ_MAX_BINDING_LEN-1] = 0; | ||
303 | if (cmd == OZ_IOCTL_ADD_BINDING) | ||
304 | oz_binding_add(b.name); | ||
305 | else | ||
306 | oz_binding_remove(b.name); | ||
307 | } | ||
308 | break; | ||
309 | } | ||
310 | return rc; | ||
311 | } | ||
312 | /*------------------------------------------------------------------------------ | ||
313 | * Context: process | ||
314 | */ | ||
315 | unsigned int oz_cdev_poll(struct file *filp, poll_table *wait) | ||
316 | { | ||
317 | unsigned int ret = 0; | ||
318 | struct oz_cdev *dev = filp->private_data; | ||
319 | oz_trace("Poll called wait = %p\n", wait); | ||
320 | spin_lock_bh(&dev->lock); | ||
321 | if (dev->active_pd) { | ||
322 | struct oz_serial_ctx *ctx = oz_cdev_claim_ctx(dev->active_pd); | ||
323 | if (ctx) { | ||
324 | if (ctx->rd_in != ctx->rd_out) | ||
325 | ret |= POLLIN | POLLRDNORM; | ||
326 | oz_cdev_release_ctx(ctx); | ||
327 | } | ||
328 | } | ||
329 | spin_unlock_bh(&dev->lock); | ||
330 | if (wait) | ||
331 | poll_wait(filp, &dev->rdq, wait); | ||
332 | return ret; | ||
333 | } | ||
334 | /*------------------------------------------------------------------------------ | ||
335 | */ | ||
336 | const struct file_operations oz_fops = { | ||
337 | .owner = THIS_MODULE, | ||
338 | .open = oz_cdev_open, | ||
339 | .release = oz_cdev_release, | ||
340 | .read = oz_cdev_read, | ||
341 | .write = oz_cdev_write, | ||
342 | .unlocked_ioctl = oz_cdev_ioctl, | ||
343 | .poll = oz_cdev_poll | ||
344 | }; | ||
345 | /*------------------------------------------------------------------------------ | ||
346 | * Context: process | ||
347 | */ | ||
348 | int oz_cdev_register(void) | ||
349 | { | ||
350 | int err; | ||
351 | memset(&g_cdev, 0, sizeof(g_cdev)); | ||
352 | err = alloc_chrdev_region(&g_cdev.devnum, 0, 1, "ozwpan"); | ||
353 | if (err < 0) | ||
354 | return err; | ||
355 | oz_trace("Alloc dev number %d:%d\n", MAJOR(g_cdev.devnum), | ||
356 | MINOR(g_cdev.devnum)); | ||
357 | cdev_init(&g_cdev.cdev, &oz_fops); | ||
358 | g_cdev.cdev.owner = THIS_MODULE; | ||
359 | g_cdev.cdev.ops = &oz_fops; | ||
360 | spin_lock_init(&g_cdev.lock); | ||
361 | init_waitqueue_head(&g_cdev.rdq); | ||
362 | err = cdev_add(&g_cdev.cdev, g_cdev.devnum, 1); | ||
363 | return 0; | ||
364 | } | ||
365 | /*------------------------------------------------------------------------------ | ||
366 | * Context: process | ||
367 | */ | ||
368 | int oz_cdev_deregister(void) | ||
369 | { | ||
370 | cdev_del(&g_cdev.cdev); | ||
371 | unregister_chrdev_region(g_cdev.devnum, 1); | ||
372 | return 0; | ||
373 | } | ||
374 | /*------------------------------------------------------------------------------ | ||
375 | * Context: process | ||
376 | */ | ||
377 | int oz_cdev_init(void) | ||
378 | { | ||
379 | oz_event_log(OZ_EVT_SERVICE, 1, OZ_APPID_SERIAL, 0, 0); | ||
380 | oz_app_enable(OZ_APPID_SERIAL, 1); | ||
381 | return 0; | ||
382 | } | ||
383 | /*------------------------------------------------------------------------------ | ||
384 | * Context: process | ||
385 | */ | ||
386 | void oz_cdev_term(void) | ||
387 | { | ||
388 | oz_event_log(OZ_EVT_SERVICE, 2, OZ_APPID_SERIAL, 0, 0); | ||
389 | oz_app_enable(OZ_APPID_SERIAL, 0); | ||
390 | } | ||
391 | /*------------------------------------------------------------------------------ | ||
392 | * Context: softirq-serialized | ||
393 | */ | ||
394 | int oz_cdev_start(struct oz_pd *pd, int resume) | ||
395 | { | ||
396 | struct oz_serial_ctx *ctx; | ||
397 | struct oz_serial_ctx *old_ctx = 0; | ||
398 | oz_event_log(OZ_EVT_SERVICE, 3, OZ_APPID_SERIAL, 0, resume); | ||
399 | if (resume) { | ||
400 | oz_trace("Serial service resumed.\n"); | ||
401 | return 0; | ||
402 | } | ||
403 | ctx = (struct oz_serial_ctx *) | ||
404 | oz_alloc(sizeof(struct oz_serial_ctx), GFP_ATOMIC); | ||
405 | if (ctx == 0) | ||
406 | return -1; | ||
407 | memset(ctx, 0, sizeof(struct oz_serial_ctx)); | ||
408 | atomic_set(&ctx->ref_count, 1); | ||
409 | ctx->tx_seq_num = 1; | ||
410 | spin_lock_bh(&pd->app_lock[OZ_APPID_SERIAL-1]); | ||
411 | old_ctx = pd->app_ctx[OZ_APPID_SERIAL-1]; | ||
412 | if (old_ctx) { | ||
413 | spin_unlock_bh(&pd->app_lock[OZ_APPID_SERIAL-1]); | ||
414 | oz_free(ctx); | ||
415 | } else { | ||
416 | pd->app_ctx[OZ_APPID_SERIAL-1] = ctx; | ||
417 | spin_unlock_bh(&pd->app_lock[OZ_APPID_SERIAL-1]); | ||
418 | } | ||
419 | spin_lock(&g_cdev.lock); | ||
420 | if ((g_cdev.active_pd == 0) && | ||
421 | (memcmp(pd->mac_addr, g_cdev.active_addr, ETH_ALEN) == 0)) { | ||
422 | oz_pd_get(pd); | ||
423 | g_cdev.active_pd = pd; | ||
424 | oz_trace("Active PD arrived.\n"); | ||
425 | } | ||
426 | spin_unlock(&g_cdev.lock); | ||
427 | oz_trace("Serial service started.\n"); | ||
428 | return 0; | ||
429 | } | ||
430 | /*------------------------------------------------------------------------------ | ||
431 | * Context: softirq or process | ||
432 | */ | ||
433 | void oz_cdev_stop(struct oz_pd *pd, int pause) | ||
434 | { | ||
435 | struct oz_serial_ctx *ctx; | ||
436 | oz_event_log(OZ_EVT_SERVICE, 4, OZ_APPID_SERIAL, 0, pause); | ||
437 | if (pause) { | ||
438 | oz_trace("Serial service paused.\n"); | ||
439 | return; | ||
440 | } | ||
441 | spin_lock_bh(&pd->app_lock[OZ_APPID_SERIAL-1]); | ||
442 | ctx = (struct oz_serial_ctx *)pd->app_ctx[OZ_APPID_SERIAL-1]; | ||
443 | pd->app_ctx[OZ_APPID_SERIAL-1] = 0; | ||
444 | spin_unlock_bh(&pd->app_lock[OZ_APPID_SERIAL-1]); | ||
445 | if (ctx) | ||
446 | oz_cdev_release_ctx(ctx); | ||
447 | spin_lock(&g_cdev.lock); | ||
448 | if (pd == g_cdev.active_pd) | ||
449 | g_cdev.active_pd = 0; | ||
450 | else | ||
451 | pd = 0; | ||
452 | spin_unlock(&g_cdev.lock); | ||
453 | if (pd) { | ||
454 | oz_pd_put(pd); | ||
455 | oz_trace("Active PD departed.\n"); | ||
456 | } | ||
457 | oz_trace("Serial service stopped.\n"); | ||
458 | } | ||
459 | /*------------------------------------------------------------------------------ | ||
460 | * Context: softirq-serialized | ||
461 | */ | ||
462 | void oz_cdev_rx(struct oz_pd *pd, struct oz_elt *elt) | ||
463 | { | ||
464 | struct oz_serial_ctx *ctx; | ||
465 | struct oz_app_hdr *app_hdr; | ||
466 | u8 *data; | ||
467 | int len; | ||
468 | int space; | ||
469 | int copy_sz; | ||
470 | int ix; | ||
471 | |||
472 | ctx = oz_cdev_claim_ctx(pd); | ||
473 | if (ctx == 0) { | ||
474 | oz_trace("Cannot claim serial context.\n"); | ||
475 | return; | ||
476 | } | ||
477 | |||
478 | app_hdr = (struct oz_app_hdr *)(elt+1); | ||
479 | /* If sequence number is non-zero then check it is not a duplicate. | ||
480 | */ | ||
481 | if (app_hdr->elt_seq_num != 0) { | ||
482 | if (((ctx->rx_seq_num - app_hdr->elt_seq_num) & 0x80) == 0) { | ||
483 | /* Reject duplicate element. */ | ||
484 | oz_trace("Duplicate element:%02x %02x\n", | ||
485 | app_hdr->elt_seq_num, ctx->rx_seq_num); | ||
486 | goto out; | ||
487 | } | ||
488 | } | ||
489 | ctx->rx_seq_num = app_hdr->elt_seq_num; | ||
490 | len = elt->length - sizeof(struct oz_app_hdr); | ||
491 | data = ((u8 *)(elt+1)) + sizeof(struct oz_app_hdr); | ||
492 | if (len <= 0) | ||
493 | goto out; | ||
494 | space = ctx->rd_out - ctx->rd_in - 1; | ||
495 | if (space < 0) | ||
496 | space += OZ_RD_BUF_SZ; | ||
497 | if (len > space) { | ||
498 | oz_trace("Not enough space:%d %d\n", len, space); | ||
499 | len = space; | ||
500 | } | ||
501 | ix = ctx->rd_in; | ||
502 | copy_sz = OZ_RD_BUF_SZ - ix; | ||
503 | if (copy_sz > len) | ||
504 | copy_sz = len; | ||
505 | memcpy(&ctx->rd_buf[ix], data, copy_sz); | ||
506 | len -= copy_sz; | ||
507 | ix += copy_sz; | ||
508 | if (ix == OZ_RD_BUF_SZ) | ||
509 | ix = 0; | ||
510 | if (len) { | ||
511 | memcpy(ctx->rd_buf, data+copy_sz, len); | ||
512 | ix = len; | ||
513 | } | ||
514 | ctx->rd_in = ix; | ||
515 | wake_up(&g_cdev.rdq); | ||
516 | out: | ||
517 | oz_cdev_release_ctx(ctx); | ||
518 | } | ||
519 | /*------------------------------------------------------------------------------ | ||
520 | * Context: softirq | ||
521 | */ | ||
522 | void oz_cdev_heartbeat(struct oz_pd *pd) | ||
523 | { | ||
524 | } | ||
diff --git a/drivers/staging/ozwpan/ozcdev.h b/drivers/staging/ozwpan/ozcdev.h new file mode 100644 index 00000000000..698014bb8d7 --- /dev/null +++ b/drivers/staging/ozwpan/ozcdev.h | |||
@@ -0,0 +1,18 @@ | |||
1 | /* ----------------------------------------------------------------------------- | ||
2 | * Copyright (c) 2011 Ozmo Inc | ||
3 | * Released under the GNU General Public License Version 2 (GPLv2). | ||
4 | * ----------------------------------------------------------------------------- | ||
5 | */ | ||
6 | #ifndef _OZCDEV_H | ||
7 | #define _OZCDEV_H | ||
8 | |||
9 | int oz_cdev_register(void); | ||
10 | int oz_cdev_deregister(void); | ||
11 | int oz_cdev_init(void); | ||
12 | void oz_cdev_term(void); | ||
13 | int oz_cdev_start(struct oz_pd *pd, int resume); | ||
14 | void oz_cdev_stop(struct oz_pd *pd, int pause); | ||
15 | void oz_cdev_rx(struct oz_pd *pd, struct oz_elt *elt); | ||
16 | void oz_cdev_heartbeat(struct oz_pd *pd); | ||
17 | |||
18 | #endif /* _OZCDEV_H */ | ||