1*10465441SEvalZero /*
2*10465441SEvalZero * Copyright (c) 2006-2018, RT-Thread Development Team
3*10465441SEvalZero *
4*10465441SEvalZero * SPDX-License-Identifier: Apache-2.0
5*10465441SEvalZero *
6*10465441SEvalZero * Change Logs:
7*10465441SEvalZero * Date Author Notes
8*10465441SEvalZero * 2012-09-30 Bernard first version.
9*10465441SEvalZero */
10*10465441SEvalZero
11*10465441SEvalZero #include <rthw.h>
12*10465441SEvalZero #include <rtthread.h>
13*10465441SEvalZero #include <rtdevice.h>
14*10465441SEvalZero
15*10465441SEvalZero #include "audio_pipe.h"
16*10465441SEvalZero
_rt_pipe_resume_writer(struct rt_audio_pipe * pipe)17*10465441SEvalZero static void _rt_pipe_resume_writer(struct rt_audio_pipe *pipe)
18*10465441SEvalZero {
19*10465441SEvalZero if (!rt_list_isempty(&pipe->suspended_write_list))
20*10465441SEvalZero {
21*10465441SEvalZero rt_thread_t thread;
22*10465441SEvalZero
23*10465441SEvalZero RT_ASSERT(pipe->flag & RT_PIPE_FLAG_BLOCK_WR);
24*10465441SEvalZero
25*10465441SEvalZero /* get suspended thread */
26*10465441SEvalZero thread = rt_list_entry(pipe->suspended_write_list.next,
27*10465441SEvalZero struct rt_thread,
28*10465441SEvalZero tlist);
29*10465441SEvalZero
30*10465441SEvalZero /* resume the write thread */
31*10465441SEvalZero rt_thread_resume(thread);
32*10465441SEvalZero
33*10465441SEvalZero rt_schedule();
34*10465441SEvalZero }
35*10465441SEvalZero }
36*10465441SEvalZero
rt_pipe_read(rt_device_t dev,rt_off_t pos,void * buffer,rt_size_t size)37*10465441SEvalZero static rt_size_t rt_pipe_read(rt_device_t dev,
38*10465441SEvalZero rt_off_t pos,
39*10465441SEvalZero void *buffer,
40*10465441SEvalZero rt_size_t size)
41*10465441SEvalZero {
42*10465441SEvalZero rt_uint32_t level;
43*10465441SEvalZero rt_thread_t thread;
44*10465441SEvalZero struct rt_audio_pipe *pipe;
45*10465441SEvalZero rt_size_t read_nbytes;
46*10465441SEvalZero
47*10465441SEvalZero pipe = (struct rt_audio_pipe *)dev;
48*10465441SEvalZero RT_ASSERT(pipe != RT_NULL);
49*10465441SEvalZero
50*10465441SEvalZero if (!(pipe->flag & RT_PIPE_FLAG_BLOCK_RD))
51*10465441SEvalZero {
52*10465441SEvalZero level = rt_hw_interrupt_disable();
53*10465441SEvalZero read_nbytes = rt_ringbuffer_get(&(pipe->ringbuffer), buffer, size);
54*10465441SEvalZero
55*10465441SEvalZero /* if the ringbuffer is empty, there won't be any writer waiting */
56*10465441SEvalZero if (read_nbytes)
57*10465441SEvalZero _rt_pipe_resume_writer(pipe);
58*10465441SEvalZero
59*10465441SEvalZero rt_hw_interrupt_enable(level);
60*10465441SEvalZero
61*10465441SEvalZero return read_nbytes;
62*10465441SEvalZero }
63*10465441SEvalZero
64*10465441SEvalZero thread = rt_thread_self();
65*10465441SEvalZero
66*10465441SEvalZero /* current context checking */
67*10465441SEvalZero RT_DEBUG_NOT_IN_INTERRUPT;
68*10465441SEvalZero
69*10465441SEvalZero do {
70*10465441SEvalZero level = rt_hw_interrupt_disable();
71*10465441SEvalZero read_nbytes = rt_ringbuffer_get(&(pipe->ringbuffer), buffer, size);
72*10465441SEvalZero if (read_nbytes == 0)
73*10465441SEvalZero {
74*10465441SEvalZero rt_thread_suspend(thread);
75*10465441SEvalZero /* waiting on suspended read list */
76*10465441SEvalZero rt_list_insert_before(&(pipe->suspended_read_list),
77*10465441SEvalZero &(thread->tlist));
78*10465441SEvalZero rt_hw_interrupt_enable(level);
79*10465441SEvalZero
80*10465441SEvalZero rt_schedule();
81*10465441SEvalZero }
82*10465441SEvalZero else
83*10465441SEvalZero {
84*10465441SEvalZero _rt_pipe_resume_writer(pipe);
85*10465441SEvalZero rt_hw_interrupt_enable(level);
86*10465441SEvalZero break;
87*10465441SEvalZero }
88*10465441SEvalZero } while (read_nbytes == 0);
89*10465441SEvalZero
90*10465441SEvalZero return read_nbytes;
91*10465441SEvalZero }
92*10465441SEvalZero
_rt_pipe_resume_reader(struct rt_audio_pipe * pipe)93*10465441SEvalZero static void _rt_pipe_resume_reader(struct rt_audio_pipe *pipe)
94*10465441SEvalZero {
95*10465441SEvalZero if (pipe->parent.rx_indicate)
96*10465441SEvalZero pipe->parent.rx_indicate(&pipe->parent,
97*10465441SEvalZero rt_ringbuffer_data_len(&pipe->ringbuffer));
98*10465441SEvalZero
99*10465441SEvalZero if (!rt_list_isempty(&pipe->suspended_read_list))
100*10465441SEvalZero {
101*10465441SEvalZero rt_thread_t thread;
102*10465441SEvalZero
103*10465441SEvalZero RT_ASSERT(pipe->flag & RT_PIPE_FLAG_BLOCK_RD);
104*10465441SEvalZero
105*10465441SEvalZero /* get suspended thread */
106*10465441SEvalZero thread = rt_list_entry(pipe->suspended_read_list.next,
107*10465441SEvalZero struct rt_thread,
108*10465441SEvalZero tlist);
109*10465441SEvalZero
110*10465441SEvalZero /* resume the read thread */
111*10465441SEvalZero rt_thread_resume(thread);
112*10465441SEvalZero
113*10465441SEvalZero rt_schedule();
114*10465441SEvalZero }
115*10465441SEvalZero }
116*10465441SEvalZero
rt_pipe_write(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t size)117*10465441SEvalZero static rt_size_t rt_pipe_write(rt_device_t dev,
118*10465441SEvalZero rt_off_t pos,
119*10465441SEvalZero const void *buffer,
120*10465441SEvalZero rt_size_t size)
121*10465441SEvalZero {
122*10465441SEvalZero rt_uint32_t level;
123*10465441SEvalZero rt_thread_t thread;
124*10465441SEvalZero struct rt_audio_pipe *pipe;
125*10465441SEvalZero rt_size_t write_nbytes;
126*10465441SEvalZero
127*10465441SEvalZero pipe = (struct rt_audio_pipe *)dev;
128*10465441SEvalZero RT_ASSERT(pipe != RT_NULL);
129*10465441SEvalZero
130*10465441SEvalZero if ((pipe->flag & RT_PIPE_FLAG_FORCE_WR) ||
131*10465441SEvalZero !(pipe->flag & RT_PIPE_FLAG_BLOCK_WR))
132*10465441SEvalZero {
133*10465441SEvalZero level = rt_hw_interrupt_disable();
134*10465441SEvalZero
135*10465441SEvalZero if (pipe->flag & RT_PIPE_FLAG_FORCE_WR)
136*10465441SEvalZero write_nbytes = rt_ringbuffer_put_force(&(pipe->ringbuffer),
137*10465441SEvalZero buffer, size);
138*10465441SEvalZero else
139*10465441SEvalZero write_nbytes = rt_ringbuffer_put(&(pipe->ringbuffer),
140*10465441SEvalZero buffer, size);
141*10465441SEvalZero
142*10465441SEvalZero _rt_pipe_resume_reader(pipe);
143*10465441SEvalZero
144*10465441SEvalZero rt_hw_interrupt_enable(level);
145*10465441SEvalZero
146*10465441SEvalZero return write_nbytes;
147*10465441SEvalZero }
148*10465441SEvalZero
149*10465441SEvalZero thread = rt_thread_self();
150*10465441SEvalZero
151*10465441SEvalZero /* current context checking */
152*10465441SEvalZero RT_DEBUG_NOT_IN_INTERRUPT;
153*10465441SEvalZero
154*10465441SEvalZero do {
155*10465441SEvalZero level = rt_hw_interrupt_disable();
156*10465441SEvalZero write_nbytes = rt_ringbuffer_put(&(pipe->ringbuffer), buffer, size);
157*10465441SEvalZero if (write_nbytes == 0)
158*10465441SEvalZero {
159*10465441SEvalZero /* pipe full, waiting on suspended write list */
160*10465441SEvalZero rt_thread_suspend(thread);
161*10465441SEvalZero /* waiting on suspended read list */
162*10465441SEvalZero rt_list_insert_before(&(pipe->suspended_write_list),
163*10465441SEvalZero &(thread->tlist));
164*10465441SEvalZero rt_hw_interrupt_enable(level);
165*10465441SEvalZero
166*10465441SEvalZero rt_schedule();
167*10465441SEvalZero }
168*10465441SEvalZero else
169*10465441SEvalZero {
170*10465441SEvalZero _rt_pipe_resume_reader(pipe);
171*10465441SEvalZero rt_hw_interrupt_enable(level);
172*10465441SEvalZero break;
173*10465441SEvalZero }
174*10465441SEvalZero } while (write_nbytes == 0);
175*10465441SEvalZero
176*10465441SEvalZero return write_nbytes;
177*10465441SEvalZero }
178*10465441SEvalZero
rt_pipe_control(rt_device_t dev,int cmd,void * args)179*10465441SEvalZero static rt_err_t rt_pipe_control(rt_device_t dev, int cmd, void *args)
180*10465441SEvalZero {
181*10465441SEvalZero struct rt_audio_pipe *pipe;
182*10465441SEvalZero
183*10465441SEvalZero pipe = (struct rt_audio_pipe *)dev;
184*10465441SEvalZero
185*10465441SEvalZero if (cmd == PIPE_CTRL_GET_SPACE && args)
186*10465441SEvalZero *(rt_size_t*)args = rt_ringbuffer_space_len(&pipe->ringbuffer);
187*10465441SEvalZero return RT_EOK;
188*10465441SEvalZero }
189*10465441SEvalZero
190*10465441SEvalZero #ifdef RT_USING_DEVICE_OPS
191*10465441SEvalZero const static struct rt_device_ops audio_pipe_ops =
192*10465441SEvalZero {
193*10465441SEvalZero RT_NULL,
194*10465441SEvalZero RT_NULL,
195*10465441SEvalZero RT_NULL,
196*10465441SEvalZero rt_pipe_read,
197*10465441SEvalZero rt_pipe_write,
198*10465441SEvalZero rt_pipe_control
199*10465441SEvalZero };
200*10465441SEvalZero #endif
201*10465441SEvalZero
202*10465441SEvalZero /**
203*10465441SEvalZero * This function will initialize a pipe device and put it under control of
204*10465441SEvalZero * resource management.
205*10465441SEvalZero *
206*10465441SEvalZero * @param pipe the pipe device
207*10465441SEvalZero * @param name the name of pipe device
208*10465441SEvalZero * @param flag the attribute of the pipe device
209*10465441SEvalZero * @param buf the buffer of pipe device
210*10465441SEvalZero * @param size the size of pipe device buffer
211*10465441SEvalZero *
212*10465441SEvalZero * @return the operation status, RT_EOK on successful
213*10465441SEvalZero */
rt_audio_pipe_init(struct rt_audio_pipe * pipe,const char * name,rt_int32_t flag,rt_uint8_t * buf,rt_size_t size)214*10465441SEvalZero rt_err_t rt_audio_pipe_init(struct rt_audio_pipe *pipe,
215*10465441SEvalZero const char *name,
216*10465441SEvalZero rt_int32_t flag,
217*10465441SEvalZero rt_uint8_t *buf,
218*10465441SEvalZero rt_size_t size)
219*10465441SEvalZero {
220*10465441SEvalZero RT_ASSERT(pipe);
221*10465441SEvalZero RT_ASSERT(buf);
222*10465441SEvalZero
223*10465441SEvalZero /* initialize suspended list */
224*10465441SEvalZero rt_list_init(&pipe->suspended_read_list);
225*10465441SEvalZero rt_list_init(&pipe->suspended_write_list);
226*10465441SEvalZero
227*10465441SEvalZero /* initialize ring buffer */
228*10465441SEvalZero rt_ringbuffer_init(&pipe->ringbuffer, buf, size);
229*10465441SEvalZero
230*10465441SEvalZero pipe->flag = flag;
231*10465441SEvalZero
232*10465441SEvalZero /* create pipe */
233*10465441SEvalZero pipe->parent.type = RT_Device_Class_Pipe;
234*10465441SEvalZero #ifdef RT_USING_DEVICE_OPS
235*10465441SEvalZero pipe->parent.ops = &audio_pipe_ops;
236*10465441SEvalZero #else
237*10465441SEvalZero pipe->parent.init = RT_NULL;
238*10465441SEvalZero pipe->parent.open = RT_NULL;
239*10465441SEvalZero pipe->parent.close = RT_NULL;
240*10465441SEvalZero pipe->parent.read = rt_pipe_read;
241*10465441SEvalZero pipe->parent.write = rt_pipe_write;
242*10465441SEvalZero pipe->parent.control = rt_pipe_control;
243*10465441SEvalZero #endif
244*10465441SEvalZero
245*10465441SEvalZero return rt_device_register(&(pipe->parent), name, RT_DEVICE_FLAG_RDWR);
246*10465441SEvalZero }
247*10465441SEvalZero
248*10465441SEvalZero /**
249*10465441SEvalZero * This function will detach a pipe device from resource management
250*10465441SEvalZero *
251*10465441SEvalZero * @param pipe the pipe device
252*10465441SEvalZero *
253*10465441SEvalZero * @return the operation status, RT_EOK on successful
254*10465441SEvalZero */
rt_audio_pipe_detach(struct rt_audio_pipe * pipe)255*10465441SEvalZero rt_err_t rt_audio_pipe_detach(struct rt_audio_pipe *pipe)
256*10465441SEvalZero {
257*10465441SEvalZero return rt_device_unregister(&pipe->parent);
258*10465441SEvalZero }
259*10465441SEvalZero
260*10465441SEvalZero #ifdef RT_USING_HEAP
rt_audio_pipe_create(const char * name,rt_int32_t flag,rt_size_t size)261*10465441SEvalZero rt_err_t rt_audio_pipe_create(const char *name, rt_int32_t flag, rt_size_t size)
262*10465441SEvalZero {
263*10465441SEvalZero rt_uint8_t *rb_memptr = RT_NULL;
264*10465441SEvalZero struct rt_audio_pipe *pipe = RT_NULL;
265*10465441SEvalZero
266*10465441SEvalZero /* get aligned size */
267*10465441SEvalZero size = RT_ALIGN(size, RT_ALIGN_SIZE);
268*10465441SEvalZero pipe = (struct rt_audio_pipe *)rt_calloc(1, sizeof(struct rt_audio_pipe));
269*10465441SEvalZero if (pipe == RT_NULL)
270*10465441SEvalZero return -RT_ENOMEM;
271*10465441SEvalZero
272*10465441SEvalZero /* create ring buffer of pipe */
273*10465441SEvalZero rb_memptr = rt_malloc(size);
274*10465441SEvalZero if (rb_memptr == RT_NULL)
275*10465441SEvalZero {
276*10465441SEvalZero rt_free(pipe);
277*10465441SEvalZero return -RT_ENOMEM;
278*10465441SEvalZero }
279*10465441SEvalZero
280*10465441SEvalZero return rt_audio_pipe_init(pipe, name, flag, rb_memptr, size);
281*10465441SEvalZero }
282*10465441SEvalZero
rt_audio_pipe_destroy(struct rt_audio_pipe * pipe)283*10465441SEvalZero void rt_audio_pipe_destroy(struct rt_audio_pipe *pipe)
284*10465441SEvalZero {
285*10465441SEvalZero if (pipe == RT_NULL)
286*10465441SEvalZero return;
287*10465441SEvalZero
288*10465441SEvalZero /* un-register pipe device */
289*10465441SEvalZero rt_audio_pipe_detach(pipe);
290*10465441SEvalZero
291*10465441SEvalZero /* release memory */
292*10465441SEvalZero rt_free(pipe->ringbuffer.buffer_ptr);
293*10465441SEvalZero rt_free(pipe);
294*10465441SEvalZero
295*10465441SEvalZero return;
296*10465441SEvalZero }
297*10465441SEvalZero
298*10465441SEvalZero #endif /* RT_USING_HEAP */
299