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#include <linux/types.h>
46
47
48#include <dspbridge/host_os.h>
49
50
51#include <dspbridge/dbdefs.h>
52
53
54#include <dspbridge/sync.h>
55
56
57#include <dspbridge/dspdefs.h>
58#include <dspbridge/dspchnl.h>
59#include "_tiomap.h"
60
61
62#include <dspbridge/dev.h>
63
64
65#include <dspbridge/io_sm.h>
66
67
68#define USERMODE_ADDR PAGE_OFFSET
69
70#define MAILBOX_IRQ INT_MAIL_MPU_IRQ
71
72
73static int create_chirp_list(struct list_head *list, u32 chirps);
74
75static void free_chirp_list(struct list_head *list);
76
77static int search_free_channel(struct chnl_mgr *chnl_mgr_obj,
78 u32 *chnl);
79
80
81
82
83
84
85
86int bridge_chnl_add_io_req(struct chnl_object *chnl_obj, void *host_buf,
87 u32 byte_size, u32 buf_size,
88 u32 dw_dsp_addr, u32 dw_arg)
89{
90 int status = 0;
91 struct chnl_object *pchnl = (struct chnl_object *)chnl_obj;
92 struct chnl_irp *chnl_packet_obj = NULL;
93 struct bridge_dev_context *dev_ctxt;
94 struct dev_object *dev_obj;
95 u8 dw_state;
96 bool is_eos;
97 struct chnl_mgr *chnl_mgr_obj;
98 u8 *host_sys_buf = NULL;
99 bool sched_dpc = false;
100 u16 mb_val = 0;
101
102 is_eos = (byte_size == 0);
103
104
105 if (!host_buf || !pchnl)
106 return -EFAULT;
107
108 if (is_eos && CHNL_IS_INPUT(pchnl->chnl_mode))
109 return -EPERM;
110
111
112
113
114
115 dw_state = pchnl->state;
116 if (dw_state != CHNL_STATEREADY) {
117 if (dw_state & CHNL_STATECANCEL)
118 return -ECANCELED;
119 if ((dw_state & CHNL_STATEEOS) &&
120 CHNL_IS_OUTPUT(pchnl->chnl_mode))
121 return -EPIPE;
122
123 }
124
125 dev_obj = dev_get_first();
126 dev_get_bridge_context(dev_obj, &dev_ctxt);
127 if (!dev_ctxt)
128 return -EFAULT;
129
130 if (pchnl->chnl_type == CHNL_PCPY && pchnl->chnl_id > 1 && host_buf) {
131 if (!(host_buf < (void *)USERMODE_ADDR)) {
132 host_sys_buf = host_buf;
133 goto func_cont;
134 }
135
136 host_sys_buf = kmalloc(buf_size, GFP_KERNEL);
137 if (host_sys_buf == NULL)
138 return -ENOMEM;
139
140 if (CHNL_IS_OUTPUT(pchnl->chnl_mode)) {
141 status = copy_from_user(host_sys_buf, host_buf,
142 buf_size);
143 if (status) {
144 kfree(host_sys_buf);
145 host_sys_buf = NULL;
146 return -EFAULT;
147 }
148 }
149 }
150func_cont:
151
152
153
154
155
156 chnl_mgr_obj = pchnl->chnl_mgr_obj;
157 spin_lock_bh(&chnl_mgr_obj->chnl_mgr_lock);
158 omap_mbox_disable_irq(dev_ctxt->mbox, IRQ_RX);
159 if (pchnl->chnl_type == CHNL_PCPY) {
160
161 if (CHNL_IS_OUTPUT(pchnl->chnl_mode)) {
162
163 if (byte_size > io_buf_size(
164 pchnl->chnl_mgr_obj->iomgr)) {
165 status = -EINVAL;
166 goto out;
167 }
168 }
169 }
170
171
172 if (list_empty(&pchnl->free_packets_list)) {
173 status = -EIO;
174 goto out;
175 }
176 chnl_packet_obj = list_first_entry(&pchnl->free_packets_list,
177 struct chnl_irp, link);
178 list_del(&chnl_packet_obj->link);
179
180
181 chnl_packet_obj->host_user_buf = chnl_packet_obj->host_sys_buf =
182 host_buf;
183 if (pchnl->chnl_type == CHNL_PCPY && pchnl->chnl_id > 1)
184 chnl_packet_obj->host_sys_buf = host_sys_buf;
185
186
187
188
189
190
191 chnl_packet_obj->dsp_tx_addr = dw_dsp_addr / chnl_mgr_obj->word_size;
192 chnl_packet_obj->byte_size = byte_size;
193 chnl_packet_obj->buf_size = buf_size;
194
195 chnl_packet_obj->arg = dw_arg;
196 chnl_packet_obj->status = (is_eos ? CHNL_IOCSTATEOS :
197 CHNL_IOCSTATCOMPLETE);
198 list_add_tail(&chnl_packet_obj->link, &pchnl->io_requests);
199 pchnl->cio_reqs++;
200
201
202
203
204 if (is_eos)
205 pchnl->state |= CHNL_STATEEOS;
206
207
208 io_request_chnl(chnl_mgr_obj->iomgr, pchnl,
209 (CHNL_IS_INPUT(pchnl->chnl_mode) ? IO_INPUT :
210 IO_OUTPUT), &mb_val);
211 sched_dpc = true;
212out:
213 omap_mbox_enable_irq(dev_ctxt->mbox, IRQ_RX);
214 spin_unlock_bh(&chnl_mgr_obj->chnl_mgr_lock);
215 if (mb_val != 0)
216 sm_interrupt_dsp(dev_ctxt, mb_val);
217
218
219 if (sched_dpc)
220 iosm_schedule(chnl_mgr_obj->iomgr);
221
222 return status;
223}
224
225
226
227
228
229
230
231
232
233
234int bridge_chnl_cancel_io(struct chnl_object *chnl_obj)
235{
236 struct chnl_object *pchnl = (struct chnl_object *)chnl_obj;
237 u32 chnl_id = -1;
238 s8 chnl_mode;
239 struct chnl_irp *chirp, *tmp;
240 struct chnl_mgr *chnl_mgr_obj = NULL;
241
242
243 if (!pchnl || !pchnl->chnl_mgr_obj)
244 return -EFAULT;
245
246 chnl_id = pchnl->chnl_id;
247 chnl_mode = pchnl->chnl_mode;
248 chnl_mgr_obj = pchnl->chnl_mgr_obj;
249
250
251
252 spin_lock_bh(&chnl_mgr_obj->chnl_mgr_lock);
253
254 pchnl->state |= CHNL_STATECANCEL;
255
256 if (list_empty(&pchnl->io_requests)) {
257 spin_unlock_bh(&chnl_mgr_obj->chnl_mgr_lock);
258 return 0;
259 }
260
261 if (pchnl->chnl_type == CHNL_PCPY) {
262
263 if (CHNL_IS_INPUT(pchnl->chnl_mode)) {
264 io_cancel_chnl(chnl_mgr_obj->iomgr, chnl_id);
265 } else {
266
267
268 chnl_mgr_obj->output_mask &= ~(1 << chnl_id);
269 }
270 }
271
272 list_for_each_entry_safe(chirp, tmp, &pchnl->io_requests, link) {
273 list_del(&chirp->link);
274 chirp->byte_size = 0;
275 chirp->status |= CHNL_IOCSTATCANCEL;
276 list_add_tail(&chirp->link, &pchnl->io_completions);
277 pchnl->cio_cs++;
278 pchnl->cio_reqs--;
279 }
280
281 spin_unlock_bh(&chnl_mgr_obj->chnl_mgr_lock);
282
283 return 0;
284}
285
286
287
288
289
290
291
292
293
294int bridge_chnl_close(struct chnl_object *chnl_obj)
295{
296 int status;
297 struct chnl_object *pchnl = (struct chnl_object *)chnl_obj;
298
299
300 if (!pchnl)
301 return -EFAULT;
302
303 status = bridge_chnl_cancel_io(chnl_obj);
304 if (status)
305 return status;
306
307
308 pchnl->chnl_mgr_obj->channels[pchnl->chnl_id] = NULL;
309 spin_lock_bh(&pchnl->chnl_mgr_obj->chnl_mgr_lock);
310 pchnl->chnl_mgr_obj->open_channels -= 1;
311 spin_unlock_bh(&pchnl->chnl_mgr_obj->chnl_mgr_lock);
312 if (pchnl->ntfy_obj) {
313 ntfy_delete(pchnl->ntfy_obj);
314 kfree(pchnl->ntfy_obj);
315 pchnl->ntfy_obj = NULL;
316 }
317
318 if (pchnl->sync_event) {
319 sync_reset_event(pchnl->sync_event);
320 kfree(pchnl->sync_event);
321 pchnl->sync_event = NULL;
322 }
323
324 free_chirp_list(&pchnl->io_completions);
325 pchnl->cio_cs = 0;
326
327 free_chirp_list(&pchnl->io_requests);
328 pchnl->cio_reqs = 0;
329
330 free_chirp_list(&pchnl->free_packets_list);
331
332
333 kfree(pchnl);
334
335 return status;
336}
337
338
339
340
341
342
343int bridge_chnl_create(struct chnl_mgr **channel_mgr,
344 struct dev_object *hdev_obj,
345 const struct chnl_mgrattrs *mgr_attrts)
346{
347 int status = 0;
348 struct chnl_mgr *chnl_mgr_obj = NULL;
349 u8 max_channels;
350
351
352 chnl_mgr_obj = kzalloc(sizeof(struct chnl_mgr), GFP_KERNEL);
353 if (chnl_mgr_obj) {
354
355
356
357
358
359
360 max_channels = CHNL_MAXCHANNELS + CHNL_MAXCHANNELS * CHNL_PCPY;
361
362 chnl_mgr_obj->channels = kzalloc(sizeof(struct chnl_object *)
363 * max_channels, GFP_KERNEL);
364 if (chnl_mgr_obj->channels) {
365
366 chnl_mgr_obj->type = CHNL_TYPESM;
367 chnl_mgr_obj->word_size = mgr_attrts->word_size;
368
369 chnl_mgr_obj->max_channels = max_channels;
370 chnl_mgr_obj->open_channels = 0;
371 chnl_mgr_obj->output_mask = 0;
372 chnl_mgr_obj->last_output = 0;
373 chnl_mgr_obj->dev_obj = hdev_obj;
374 spin_lock_init(&chnl_mgr_obj->chnl_mgr_lock);
375 } else {
376 status = -ENOMEM;
377 }
378 } else {
379 status = -ENOMEM;
380 }
381
382 if (status) {
383 bridge_chnl_destroy(chnl_mgr_obj);
384 *channel_mgr = NULL;
385 } else {
386
387 *channel_mgr = chnl_mgr_obj;
388 }
389 return status;
390}
391
392
393
394
395
396
397int bridge_chnl_destroy(struct chnl_mgr *hchnl_mgr)
398{
399 int status = 0;
400 struct chnl_mgr *chnl_mgr_obj = hchnl_mgr;
401 u32 chnl_id;
402
403 if (hchnl_mgr) {
404
405 for (chnl_id = 0; chnl_id < chnl_mgr_obj->max_channels;
406 chnl_id++) {
407 status =
408 bridge_chnl_close(chnl_mgr_obj->channels
409 [chnl_id]);
410 if (status)
411 dev_dbg(bridge, "%s: Error status 0x%x\n",
412 __func__, status);
413 }
414
415
416 kfree(chnl_mgr_obj->channels);
417
418
419 dev_set_chnl_mgr(chnl_mgr_obj->dev_obj, NULL);
420
421 kfree(hchnl_mgr);
422 } else {
423 status = -EFAULT;
424 }
425 return status;
426}
427
428
429
430
431
432
433int bridge_chnl_flush_io(struct chnl_object *chnl_obj, u32 timeout)
434{
435 int status = 0;
436 struct chnl_object *pchnl = (struct chnl_object *)chnl_obj;
437 s8 chnl_mode = -1;
438 struct chnl_mgr *chnl_mgr_obj;
439 struct chnl_ioc chnl_ioc_obj;
440
441 if (pchnl) {
442 if ((timeout == CHNL_IOCNOWAIT)
443 && CHNL_IS_OUTPUT(pchnl->chnl_mode)) {
444 status = -EINVAL;
445 } else {
446 chnl_mode = pchnl->chnl_mode;
447 chnl_mgr_obj = pchnl->chnl_mgr_obj;
448 }
449 } else {
450 status = -EFAULT;
451 }
452 if (!status) {
453
454
455
456 if (CHNL_IS_OUTPUT(chnl_mode)
457 && (pchnl->chnl_type == CHNL_PCPY)) {
458
459
460 while (!list_empty(&pchnl->io_requests) && !status) {
461 status = bridge_chnl_get_ioc(chnl_obj,
462 timeout, &chnl_ioc_obj);
463 if (status)
464 continue;
465
466 if (chnl_ioc_obj.status & CHNL_IOCSTATTIMEOUT)
467 status = -ETIMEDOUT;
468
469 }
470 } else {
471 status = bridge_chnl_cancel_io(chnl_obj);
472
473 pchnl->state &= ~CHNL_STATECANCEL;
474 }
475 }
476 return status;
477}
478
479
480
481
482
483
484int bridge_chnl_get_info(struct chnl_object *chnl_obj,
485 struct chnl_info *channel_info)
486{
487 int status = 0;
488 struct chnl_object *pchnl = (struct chnl_object *)chnl_obj;
489 if (channel_info != NULL) {
490 if (pchnl) {
491
492 channel_info->chnl_mgr = pchnl->chnl_mgr_obj;
493 channel_info->event_obj = pchnl->user_event;
494 channel_info->cnhl_id = pchnl->chnl_id;
495 channel_info->mode = pchnl->chnl_mode;
496 channel_info->bytes_tx = pchnl->bytes_moved;
497 channel_info->process = pchnl->process;
498 channel_info->sync_event = pchnl->sync_event;
499 channel_info->cio_cs = pchnl->cio_cs;
500 channel_info->cio_reqs = pchnl->cio_reqs;
501 channel_info->state = pchnl->state;
502 } else {
503 status = -EFAULT;
504 }
505 } else {
506 status = -EFAULT;
507 }
508 return status;
509}
510
511
512
513
514
515
516
517
518int bridge_chnl_get_ioc(struct chnl_object *chnl_obj, u32 timeout,
519 struct chnl_ioc *chan_ioc)
520{
521 int status = 0;
522 struct chnl_object *pchnl = (struct chnl_object *)chnl_obj;
523 struct chnl_irp *chnl_packet_obj;
524 int stat_sync;
525 bool dequeue_ioc = true;
526 struct chnl_ioc ioc = { NULL, 0, 0, 0, 0 };
527 u8 *host_sys_buf = NULL;
528 struct bridge_dev_context *dev_ctxt;
529 struct dev_object *dev_obj;
530
531
532 if (!chan_ioc || !pchnl) {
533 status = -EFAULT;
534 } else if (timeout == CHNL_IOCNOWAIT) {
535 if (list_empty(&pchnl->io_completions))
536 status = -EREMOTEIO;
537
538 }
539
540 dev_obj = dev_get_first();
541 dev_get_bridge_context(dev_obj, &dev_ctxt);
542 if (!dev_ctxt)
543 status = -EFAULT;
544
545 if (status)
546 goto func_end;
547
548 ioc.status = CHNL_IOCSTATCOMPLETE;
549 if (timeout !=
550 CHNL_IOCNOWAIT && list_empty(&pchnl->io_completions)) {
551 if (timeout == CHNL_IOCINFINITE)
552 timeout = SYNC_INFINITE;
553
554 stat_sync = sync_wait_on_event(pchnl->sync_event, timeout);
555 if (stat_sync == -ETIME) {
556
557 ioc.status |= CHNL_IOCSTATTIMEOUT;
558 dequeue_ioc = false;
559 } else if (stat_sync == -EPERM) {
560
561
562
563
564
565 if (list_empty(&pchnl->io_completions)) {
566 ioc.status |= CHNL_IOCSTATCANCEL;
567 dequeue_ioc = false;
568 }
569 }
570 }
571
572 spin_lock_bh(&pchnl->chnl_mgr_obj->chnl_mgr_lock);
573 omap_mbox_disable_irq(dev_ctxt->mbox, IRQ_RX);
574 if (dequeue_ioc) {
575
576 chnl_packet_obj = list_first_entry(&pchnl->io_completions,
577 struct chnl_irp, link);
578 list_del(&chnl_packet_obj->link);
579
580 pchnl->cio_cs--;
581
582
583
584
585
586 host_sys_buf = chnl_packet_obj->host_sys_buf;
587 ioc.buf = chnl_packet_obj->host_user_buf;
588 ioc.byte_size = chnl_packet_obj->byte_size;
589 ioc.buf_size = chnl_packet_obj->buf_size;
590 ioc.arg = chnl_packet_obj->arg;
591 ioc.status |= chnl_packet_obj->status;
592
593 list_add_tail(&chnl_packet_obj->link,
594 &pchnl->free_packets_list);
595 } else {
596 ioc.buf = NULL;
597 ioc.byte_size = 0;
598 ioc.arg = 0;
599 ioc.buf_size = 0;
600 }
601
602 if (!list_empty(&pchnl->io_completions)) {
603
604
605
606
607
608
609
610
611
612
613
614 sync_set_event(pchnl->sync_event);
615 } else {
616
617 sync_reset_event(pchnl->sync_event);
618 }
619 omap_mbox_enable_irq(dev_ctxt->mbox, IRQ_RX);
620 spin_unlock_bh(&pchnl->chnl_mgr_obj->chnl_mgr_lock);
621 if (dequeue_ioc
622 && (pchnl->chnl_type == CHNL_PCPY && pchnl->chnl_id > 1)) {
623 if (!(ioc.buf < (void *)USERMODE_ADDR))
624 goto func_cont;
625
626
627 if (!host_sys_buf || !ioc.buf) {
628 status = -EFAULT;
629 goto func_cont;
630 }
631 if (!CHNL_IS_INPUT(pchnl->chnl_mode))
632 goto func_cont1;
633
634
635 status = copy_to_user(ioc.buf, host_sys_buf, ioc.byte_size);
636 if (status) {
637 if (current->flags & PF_EXITING)
638 status = 0;
639 }
640 if (status)
641 status = -EFAULT;
642func_cont1:
643 kfree(host_sys_buf);
644 }
645func_cont:
646
647 *chan_ioc = ioc;
648func_end:
649 return status;
650}
651
652
653
654
655
656int bridge_chnl_get_mgr_info(struct chnl_mgr *hchnl_mgr, u32 ch_id,
657 struct chnl_mgrinfo *mgr_info)
658{
659 struct chnl_mgr *chnl_mgr_obj = (struct chnl_mgr *)hchnl_mgr;
660
661 if (!mgr_info || !hchnl_mgr)
662 return -EFAULT;
663
664 if (ch_id > CHNL_MAXCHANNELS)
665 return -ECHRNG;
666
667
668 mgr_info->chnl_obj = chnl_mgr_obj->channels[ch_id];
669 mgr_info->open_channels = chnl_mgr_obj->open_channels;
670 mgr_info->type = chnl_mgr_obj->type;
671
672 mgr_info->max_channels = chnl_mgr_obj->max_channels;
673
674 return 0;
675}
676
677
678
679
680
681int bridge_chnl_idle(struct chnl_object *chnl_obj, u32 timeout,
682 bool flush_data)
683{
684 s8 chnl_mode;
685 struct chnl_mgr *chnl_mgr_obj;
686 int status = 0;
687
688 chnl_mode = chnl_obj->chnl_mode;
689 chnl_mgr_obj = chnl_obj->chnl_mgr_obj;
690
691 if (CHNL_IS_OUTPUT(chnl_mode) && !flush_data) {
692
693 status = bridge_chnl_flush_io(chnl_obj, timeout);
694 } else {
695 status = bridge_chnl_cancel_io(chnl_obj);
696
697
698 chnl_obj->bytes_moved = 0;
699 chnl_obj->state &= ~CHNL_STATECANCEL;
700 }
701
702 return status;
703}
704
705
706
707
708
709int bridge_chnl_open(struct chnl_object **chnl,
710 struct chnl_mgr *hchnl_mgr, s8 chnl_mode,
711 u32 ch_id, const struct chnl_attr *pattrs)
712{
713 int status = 0;
714 struct chnl_mgr *chnl_mgr_obj = hchnl_mgr;
715 struct chnl_object *pchnl = NULL;
716 struct sync_object *sync_event = NULL;
717
718 *chnl = NULL;
719
720
721 if (!pattrs->uio_reqs)
722 return -EINVAL;
723
724 if (!hchnl_mgr)
725 return -EFAULT;
726
727 if (ch_id != CHNL_PICKFREE) {
728 if (ch_id >= chnl_mgr_obj->max_channels)
729 return -ECHRNG;
730 if (chnl_mgr_obj->channels[ch_id] != NULL)
731 return -EALREADY;
732 } else {
733
734 status = search_free_channel(chnl_mgr_obj, &ch_id);
735 if (status)
736 return status;
737 }
738
739
740
741 pchnl = kzalloc(sizeof(struct chnl_object), GFP_KERNEL);
742 if (!pchnl)
743 return -ENOMEM;
744
745
746 pchnl->state = CHNL_STATECANCEL;
747
748
749 status = create_chirp_list(&pchnl->free_packets_list,
750 pattrs->uio_reqs);
751 if (status)
752 goto out_err;
753
754 INIT_LIST_HEAD(&pchnl->io_requests);
755 INIT_LIST_HEAD(&pchnl->io_completions);
756
757 pchnl->chnl_packets = pattrs->uio_reqs;
758 pchnl->cio_cs = 0;
759 pchnl->cio_reqs = 0;
760
761 sync_event = kzalloc(sizeof(struct sync_object), GFP_KERNEL);
762 if (!sync_event) {
763 status = -ENOMEM;
764 goto out_err;
765 }
766 sync_init_event(sync_event);
767
768 pchnl->ntfy_obj = kmalloc(sizeof(struct ntfy_object), GFP_KERNEL);
769 if (!pchnl->ntfy_obj) {
770 status = -ENOMEM;
771 goto out_err;
772 }
773 ntfy_init(pchnl->ntfy_obj);
774
775
776 pchnl->chnl_mgr_obj = chnl_mgr_obj;
777 pchnl->chnl_id = ch_id;
778 pchnl->chnl_mode = chnl_mode;
779 pchnl->user_event = sync_event;
780 pchnl->sync_event = sync_event;
781
782 pchnl->process = current->tgid;
783 pchnl->cb_arg = 0;
784 pchnl->bytes_moved = 0;
785
786 pchnl->chnl_type = CHNL_PCPY;
787
788
789 chnl_mgr_obj->channels[pchnl->chnl_id] = pchnl;
790 spin_lock_bh(&chnl_mgr_obj->chnl_mgr_lock);
791 chnl_mgr_obj->open_channels++;
792 spin_unlock_bh(&chnl_mgr_obj->chnl_mgr_lock);
793
794 pchnl->state = CHNL_STATEREADY;
795 *chnl = pchnl;
796
797 return status;
798
799out_err:
800
801 free_chirp_list(&pchnl->io_completions);
802 free_chirp_list(&pchnl->io_requests);
803 free_chirp_list(&pchnl->free_packets_list);
804
805 kfree(sync_event);
806
807 if (pchnl->ntfy_obj) {
808 ntfy_delete(pchnl->ntfy_obj);
809 kfree(pchnl->ntfy_obj);
810 pchnl->ntfy_obj = NULL;
811 }
812 kfree(pchnl);
813
814 return status;
815}
816
817
818
819
820
821int bridge_chnl_register_notify(struct chnl_object *chnl_obj,
822 u32 event_mask, u32 notify_type,
823 struct dsp_notification *hnotification)
824{
825 int status = 0;
826
827
828 if (event_mask)
829 status = ntfy_register(chnl_obj->ntfy_obj, hnotification,
830 event_mask, notify_type);
831 else
832 status = ntfy_unregister(chnl_obj->ntfy_obj, hnotification);
833
834 return status;
835}
836
837
838
839
840
841
842
843
844
845
846
847
848
849static int create_chirp_list(struct list_head *list, u32 chirps)
850{
851 struct chnl_irp *chirp;
852 u32 i;
853
854 INIT_LIST_HEAD(list);
855
856
857 for (i = 0; i < chirps; i++) {
858 chirp = kzalloc(sizeof(struct chnl_irp), GFP_KERNEL);
859 if (!chirp)
860 break;
861 list_add_tail(&chirp->link, list);
862 }
863
864
865 if (i != chirps) {
866 free_chirp_list(list);
867 return -ENOMEM;
868 }
869
870 return 0;
871}
872
873
874
875
876
877
878static void free_chirp_list(struct list_head *chirp_list)
879{
880 struct chnl_irp *chirp, *tmp;
881
882 list_for_each_entry_safe(chirp, tmp, chirp_list, link) {
883 list_del(&chirp->link);
884 kfree(chirp);
885 }
886}
887
888
889
890
891
892static int search_free_channel(struct chnl_mgr *chnl_mgr_obj,
893 u32 *chnl)
894{
895 int status = -ENOSR;
896 u32 i;
897
898 for (i = 0; i < chnl_mgr_obj->max_channels; i++) {
899 if (chnl_mgr_obj->channels[i] == NULL) {
900 status = 0;
901 *chnl = i;
902 break;
903 }
904 }
905
906 return status;
907}
908