1beacf11bSopenharmony_ci/****************************************************************************
2beacf11bSopenharmony_ci * drivers/pipes/pipe_common.c
3beacf11bSopenharmony_ci *
4beacf11bSopenharmony_ci * Licensed to the Apache Software Foundation (ASF) under one or more
5beacf11bSopenharmony_ci * contributor license agreements.  See the NOTICE file distributed with
6beacf11bSopenharmony_ci * this work for additional information regarding copyright ownership.  The
7beacf11bSopenharmony_ci * ASF licenses this file to you under the Apache License, Version 2.0 (the
8beacf11bSopenharmony_ci * "License"); you may not use this file except in compliance with the
9beacf11bSopenharmony_ci * License.  You may obtain a copy of the License at
10beacf11bSopenharmony_ci *
11beacf11bSopenharmony_ci *   http://www.apache.org/licenses/LICENSE-2.0
12beacf11bSopenharmony_ci *
13beacf11bSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
14beacf11bSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15beacf11bSopenharmony_ci * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
16beacf11bSopenharmony_ci * License for the specific language governing permissions and limitations
17beacf11bSopenharmony_ci * under the License.
18beacf11bSopenharmony_ci *
19beacf11bSopenharmony_ci ****************************************************************************/
20beacf11bSopenharmony_ci
21beacf11bSopenharmony_ci/****************************************************************************
22beacf11bSopenharmony_ci * Included Files
23beacf11bSopenharmony_ci ****************************************************************************/
24beacf11bSopenharmony_ci
25beacf11bSopenharmony_ci#include <sys/types.h>
26beacf11bSopenharmony_ci#include <sys/stat.h>
27beacf11bSopenharmony_ci#include <sys/ioctl.h>
28beacf11bSopenharmony_ci#include <stdint.h>
29beacf11bSopenharmony_ci#include <stdbool.h>
30beacf11bSopenharmony_ci#include <stdlib.h>
31beacf11bSopenharmony_ci#include <string.h>
32beacf11bSopenharmony_ci#include <sched.h>
33beacf11bSopenharmony_ci#include <semaphore.h>
34beacf11bSopenharmony_ci#include <fcntl.h>
35beacf11bSopenharmony_ci#include <errno.h>
36beacf11bSopenharmony_ci#include <poll.h>
37beacf11bSopenharmony_ci#include "linux/wait.h"
38beacf11bSopenharmony_ci#include <assert.h>
39beacf11bSopenharmony_ci
40beacf11bSopenharmony_ci#ifdef CONFIG_DEBUG_FEATURES
41beacf11bSopenharmony_ci#  include <nuttx/arch.h>
42beacf11bSopenharmony_ci#endif
43beacf11bSopenharmony_ci#include <semaphore.h>
44beacf11bSopenharmony_ci#include <fs/driver.h>
45beacf11bSopenharmony_ci#include "pipe_common.h"
46beacf11bSopenharmony_ci#include "los_printf.h"
47beacf11bSopenharmony_ci#include "user_copy.h"
48beacf11bSopenharmony_ci#ifdef LOSCFG_KERNEL_PIPE
49beacf11bSopenharmony_ci
50beacf11bSopenharmony_ci/****************************************************************************
51beacf11bSopenharmony_ci * Pre-processor Definitions
52beacf11bSopenharmony_ci ****************************************************************************/
53beacf11bSopenharmony_ci
54beacf11bSopenharmony_ci/* CONFIG_DEV_PIPEDUMP will dump the contents of each transfer into and out
55beacf11bSopenharmony_ci * of the pipe.
56beacf11bSopenharmony_ci */
57beacf11bSopenharmony_ci
58beacf11bSopenharmony_ci#ifdef CONFIG_DEV_PIPEDUMP
59beacf11bSopenharmony_ci#  define pipe_dumpbuffer(m,a,n) lib_dumpbuffer(m,a,n)
60beacf11bSopenharmony_ci#else
61beacf11bSopenharmony_ci#  define pipe_dumpbuffer(m,a,n)
62beacf11bSopenharmony_ci#endif
63beacf11bSopenharmony_ci
64beacf11bSopenharmony_ci/****************************************************************************
65beacf11bSopenharmony_ci * Private Function Prototypes
66beacf11bSopenharmony_ci ****************************************************************************/
67beacf11bSopenharmony_ci
68beacf11bSopenharmony_cistatic void pipecommon_semtake(sem_t *sem);
69beacf11bSopenharmony_ci
70beacf11bSopenharmony_ci/****************************************************************************
71beacf11bSopenharmony_ci * Private Functions
72beacf11bSopenharmony_ci ****************************************************************************/
73beacf11bSopenharmony_ci
74beacf11bSopenharmony_ci/****************************************************************************
75beacf11bSopenharmony_ci * Name: pipecommon_semtake
76beacf11bSopenharmony_ci ****************************************************************************/
77beacf11bSopenharmony_ci
78beacf11bSopenharmony_cistatic void pipecommon_semtake(sem_t *sem)
79beacf11bSopenharmony_ci{
80beacf11bSopenharmony_ci  int ret;
81beacf11bSopenharmony_ci
82beacf11bSopenharmony_ci  do
83beacf11bSopenharmony_ci    {
84beacf11bSopenharmony_ci      /* Take the semaphore (perhaps waiting) */
85beacf11bSopenharmony_ci
86beacf11bSopenharmony_ci      ret = sem_wait(sem);
87beacf11bSopenharmony_ci
88beacf11bSopenharmony_ci    }
89beacf11bSopenharmony_ci  while (ret == -EINTR);
90beacf11bSopenharmony_ci}
91beacf11bSopenharmony_ci
92beacf11bSopenharmony_ci/****************************************************************************
93beacf11bSopenharmony_ci * Name: pipecommon_pollnotify
94beacf11bSopenharmony_ci ****************************************************************************/
95beacf11bSopenharmony_ci
96beacf11bSopenharmony_cistatic void pipecommon_pollnotify(struct pipe_dev_s *dev,
97beacf11bSopenharmony_ci                                  pollevent_t eventset)
98beacf11bSopenharmony_ci{
99beacf11bSopenharmony_ci  if (eventset & POLLERR)
100beacf11bSopenharmony_ci    {
101beacf11bSopenharmony_ci      eventset &= ~(POLLOUT | POLLIN);
102beacf11bSopenharmony_ci    }
103beacf11bSopenharmony_ci
104beacf11bSopenharmony_ci  notify_poll_with_key(&dev->wq, eventset);
105beacf11bSopenharmony_ci}
106beacf11bSopenharmony_ci
107beacf11bSopenharmony_ci/****************************************************************************
108beacf11bSopenharmony_ci * Public Functions
109beacf11bSopenharmony_ci ****************************************************************************/
110beacf11bSopenharmony_ci
111beacf11bSopenharmony_ci/****************************************************************************
112beacf11bSopenharmony_ci * Name: pipecommon_allocdev
113beacf11bSopenharmony_ci ****************************************************************************/
114beacf11bSopenharmony_ci
115beacf11bSopenharmony_cistruct pipe_dev_s *pipecommon_allocdev(size_t bufsize, const char *name)
116beacf11bSopenharmony_ci{
117beacf11bSopenharmony_ci  struct pipe_dev_s *dev = NULL;
118beacf11bSopenharmony_ci  int ret;
119beacf11bSopenharmony_ci
120beacf11bSopenharmony_ci  if (bufsize > CONFIG_DEV_PIPE_MAXSIZE)
121beacf11bSopenharmony_ci    {
122beacf11bSopenharmony_ci      return NULL;
123beacf11bSopenharmony_ci    }
124beacf11bSopenharmony_ci
125beacf11bSopenharmony_ci  /* Allocate a private structure to manage the pipe */
126beacf11bSopenharmony_ci
127beacf11bSopenharmony_ci  dev = (struct pipe_dev_s *)malloc(sizeof(struct pipe_dev_s));
128beacf11bSopenharmony_ci  if (dev)
129beacf11bSopenharmony_ci    {
130beacf11bSopenharmony_ci      /* Initialize the private structure */
131beacf11bSopenharmony_ci
132beacf11bSopenharmony_ci      (void)memset_s(dev, sizeof(struct pipe_dev_s), 0, sizeof(struct pipe_dev_s));
133beacf11bSopenharmony_ci      ret = strcpy_s(dev->name, sizeof(dev->name), name);
134beacf11bSopenharmony_ci      if (ret < 0)
135beacf11bSopenharmony_ci        {
136beacf11bSopenharmony_ci          free(dev);
137beacf11bSopenharmony_ci          return NULL;
138beacf11bSopenharmony_ci        }
139beacf11bSopenharmony_ci      sem_init(&dev->d_bfsem, 0, 1);
140beacf11bSopenharmony_ci      sem_init(&dev->d_rdsem, 0, 0);
141beacf11bSopenharmony_ci      sem_init(&dev->d_wrsem, 0, 0);
142beacf11bSopenharmony_ci      LOS_ListInit(&dev->wq.poll_queue);
143beacf11bSopenharmony_ci     /* The read/write wait semaphores are used for signaling and, hence,
144beacf11bSopenharmony_ci      * should not have priority inheritance enabled.
145beacf11bSopenharmony_ci      */
146beacf11bSopenharmony_ci
147beacf11bSopenharmony_ci      dev->d_bufsize = bufsize;
148beacf11bSopenharmony_ci    }
149beacf11bSopenharmony_ci
150beacf11bSopenharmony_ci  return dev;
151beacf11bSopenharmony_ci}
152beacf11bSopenharmony_ci
153beacf11bSopenharmony_ci/****************************************************************************
154beacf11bSopenharmony_ci * Name: pipecommon_freedev
155beacf11bSopenharmony_ci ****************************************************************************/
156beacf11bSopenharmony_ci
157beacf11bSopenharmony_civoid pipecommon_freedev(struct pipe_dev_s *dev)
158beacf11bSopenharmony_ci{
159beacf11bSopenharmony_ci  sem_destroy(&dev->d_bfsem);
160beacf11bSopenharmony_ci  sem_destroy(&dev->d_rdsem);
161beacf11bSopenharmony_ci  sem_destroy(&dev->d_wrsem);
162beacf11bSopenharmony_ci  free(dev);
163beacf11bSopenharmony_ci}
164beacf11bSopenharmony_ci
165beacf11bSopenharmony_ci/****************************************************************************
166beacf11bSopenharmony_ci * Name: pipecommon_open
167beacf11bSopenharmony_ci ****************************************************************************/
168beacf11bSopenharmony_ci
169beacf11bSopenharmony_ciint pipecommon_open(struct file *filep)
170beacf11bSopenharmony_ci{
171beacf11bSopenharmony_ci  struct Vnode      *vnode = filep->f_vnode;
172beacf11bSopenharmony_ci  struct pipe_dev_s *dev   = (struct pipe_dev_s *)((struct drv_data *)vnode->data)->priv;
173beacf11bSopenharmony_ci  int                    sval;
174beacf11bSopenharmony_ci  int                    ret;
175beacf11bSopenharmony_ci
176beacf11bSopenharmony_ci  if (dev == NULL)
177beacf11bSopenharmony_ci    {
178beacf11bSopenharmony_ci      return -EINVAL;
179beacf11bSopenharmony_ci    }
180beacf11bSopenharmony_ci
181beacf11bSopenharmony_ci  /* Make sure that we have exclusive access to the device structure.  The
182beacf11bSopenharmony_ci   * sem_wait() call should fail only if we are awakened by a signal.
183beacf11bSopenharmony_ci   */
184beacf11bSopenharmony_ci
185beacf11bSopenharmony_ci  ret = sem_wait(&dev->d_bfsem);
186beacf11bSopenharmony_ci  if (ret < 0)
187beacf11bSopenharmony_ci    {
188beacf11bSopenharmony_ci      PRINT_ERR("ERROR: sem_wait failed: %d\n", ret);
189beacf11bSopenharmony_ci      return ret;
190beacf11bSopenharmony_ci    }
191beacf11bSopenharmony_ci
192beacf11bSopenharmony_ci  /* If this the first reference on the device, then allocate the buffer.
193beacf11bSopenharmony_ci   * In the case of policy 1, the buffer already be present when the pipe
194beacf11bSopenharmony_ci   * is first opened.
195beacf11bSopenharmony_ci   */
196beacf11bSopenharmony_ci
197beacf11bSopenharmony_ci  if (vnode->useCount == 1 && dev->d_buffer == NULL)
198beacf11bSopenharmony_ci    {
199beacf11bSopenharmony_ci      dev->d_buffer = (uint8_t *)malloc(dev->d_bufsize);
200beacf11bSopenharmony_ci      if (!dev->d_buffer)
201beacf11bSopenharmony_ci        {
202beacf11bSopenharmony_ci          (void)sem_post(&dev->d_bfsem);
203beacf11bSopenharmony_ci          return -ENOMEM;
204beacf11bSopenharmony_ci        }
205beacf11bSopenharmony_ci    }
206beacf11bSopenharmony_ci
207beacf11bSopenharmony_ci
208beacf11bSopenharmony_ci  /* If opened for writing, increment the count of writers on the pipe instance */
209beacf11bSopenharmony_ci
210beacf11bSopenharmony_ci  if ((filep->f_oflags & O_WRONLY) != 0)
211beacf11bSopenharmony_ci    {
212beacf11bSopenharmony_ci      dev->d_nwriters++;
213beacf11bSopenharmony_ci
214beacf11bSopenharmony_ci      /* If this this is the first writer, then the read semaphore indicates the
215beacf11bSopenharmony_ci       * number of readers waiting for the first writer.  Wake them all up.
216beacf11bSopenharmony_ci       */
217beacf11bSopenharmony_ci
218beacf11bSopenharmony_ci      if (dev->d_nwriters == 1)
219beacf11bSopenharmony_ci        {
220beacf11bSopenharmony_ci          while (sem_getvalue(&dev->d_rdsem, &sval) == 0 && sval == 0)
221beacf11bSopenharmony_ci            {
222beacf11bSopenharmony_ci              sem_post(&dev->d_rdsem);
223beacf11bSopenharmony_ci            }
224beacf11bSopenharmony_ci        }
225beacf11bSopenharmony_ci    }
226beacf11bSopenharmony_ci
227beacf11bSopenharmony_ci  /* If opened for reading, increment the count of reader on on the pipe instance */
228beacf11bSopenharmony_ci
229beacf11bSopenharmony_ci  if ((filep->f_oflags & O_WRONLY) == 0)
230beacf11bSopenharmony_ci    {
231beacf11bSopenharmony_ci      dev->d_nreaders++;
232beacf11bSopenharmony_ci    }
233beacf11bSopenharmony_ci
234beacf11bSopenharmony_ci  /* If opened for read-only, then wait for either (1) at least one writer
235beacf11bSopenharmony_ci   * on the pipe (policy == 0), or (2) until there is buffered data to be
236beacf11bSopenharmony_ci   * read (policy == 1).
237beacf11bSopenharmony_ci   */
238beacf11bSopenharmony_ci
239beacf11bSopenharmony_ci  (void)sem_post(&dev->d_bfsem);
240beacf11bSopenharmony_ci
241beacf11bSopenharmony_ci  if ((filep->f_oflags & O_WRONLY) == 0 &&       /* Read-only */
242beacf11bSopenharmony_ci      dev->d_nwriters < 1 &&                     /* No writers on the pipe */
243beacf11bSopenharmony_ci      dev->d_wrndx == dev->d_rdndx)              /* Buffer is empty */
244beacf11bSopenharmony_ci    {
245beacf11bSopenharmony_ci      /* NOTE: d_rdsem is normally used when the read logic waits for more
246beacf11bSopenharmony_ci       * data to be written.  But until the first writer has opened the
247beacf11bSopenharmony_ci       * pipe, the meaning is different: it is used prevent O_RDONLY open
248beacf11bSopenharmony_ci       * calls from returning until there is at least one writer on the pipe.
249beacf11bSopenharmony_ci       * This is required both by spec and also because it prevents
250beacf11bSopenharmony_ci       * subsequent read() calls from returning end-of-file because there is
251beacf11bSopenharmony_ci       * no writer on the pipe.
252beacf11bSopenharmony_ci       */
253beacf11bSopenharmony_ci
254beacf11bSopenharmony_ci      ret = sem_wait(&dev->d_rdsem);
255beacf11bSopenharmony_ci      if (ret < 0)
256beacf11bSopenharmony_ci        {
257beacf11bSopenharmony_ci          /* The sem_wait() call should fail only if we are awakened by
258beacf11bSopenharmony_ci           * a signal.
259beacf11bSopenharmony_ci           */
260beacf11bSopenharmony_ci
261beacf11bSopenharmony_ci          PRINT_ERR("ERROR: sem_wait failed: %d\n", ret);
262beacf11bSopenharmony_ci
263beacf11bSopenharmony_ci          /* Immediately close the pipe that we just opened */
264beacf11bSopenharmony_ci
265beacf11bSopenharmony_ci          (void)pipecommon_close(filep);
266beacf11bSopenharmony_ci        }
267beacf11bSopenharmony_ci    }
268beacf11bSopenharmony_ci  VnodeHold();
269beacf11bSopenharmony_ci  vnode->useCount++;
270beacf11bSopenharmony_ci  VnodeDrop();
271beacf11bSopenharmony_ci  return ret;
272beacf11bSopenharmony_ci}
273beacf11bSopenharmony_ci
274beacf11bSopenharmony_ci/****************************************************************************
275beacf11bSopenharmony_ci * Name: pipecommon_close
276beacf11bSopenharmony_ci ****************************************************************************/
277beacf11bSopenharmony_ci
278beacf11bSopenharmony_ciint pipecommon_close(struct file *filep)
279beacf11bSopenharmony_ci{
280beacf11bSopenharmony_ci  struct Vnode      *vnode = filep->f_vnode;
281beacf11bSopenharmony_ci  struct pipe_dev_s *dev   = (struct pipe_dev_s *)((struct drv_data *)vnode->data)->priv;
282beacf11bSopenharmony_ci  int                    sval;
283beacf11bSopenharmony_ci
284beacf11bSopenharmony_ci  if (dev == NULL || filep->f_vnode->useCount <= 1)
285beacf11bSopenharmony_ci    {
286beacf11bSopenharmony_ci      return -EINVAL;
287beacf11bSopenharmony_ci    }
288beacf11bSopenharmony_ci
289beacf11bSopenharmony_ci  /* Make sure that we have exclusive access to the device structure.
290beacf11bSopenharmony_ci   * NOTE: close() is supposed to return EINTR if interrupted, however
291beacf11bSopenharmony_ci   * I've never seen anyone check that.
292beacf11bSopenharmony_ci   */
293beacf11bSopenharmony_ci
294beacf11bSopenharmony_ci  pipecommon_semtake(&dev->d_bfsem);
295beacf11bSopenharmony_ci
296beacf11bSopenharmony_ci  /* Decrement the number of references on the pipe.  Check if there are
297beacf11bSopenharmony_ci   * still outstanding references to the pipe.
298beacf11bSopenharmony_ci   */
299beacf11bSopenharmony_ci
300beacf11bSopenharmony_ci  /* Check if the decremented vnode reference count would go to zero */
301beacf11bSopenharmony_ci
302beacf11bSopenharmony_ci  if (vnode->useCount > 1)
303beacf11bSopenharmony_ci    {
304beacf11bSopenharmony_ci      /* More references.. If opened for writing, decrement the count of
305beacf11bSopenharmony_ci       * writers on the pipe instance.
306beacf11bSopenharmony_ci       */
307beacf11bSopenharmony_ci
308beacf11bSopenharmony_ci      if ((filep->f_oflags & O_WRONLY) != 0)
309beacf11bSopenharmony_ci        {
310beacf11bSopenharmony_ci          /* If there are no longer any writers on the pipe, then notify all of the
311beacf11bSopenharmony_ci           * waiting readers that they must return end-of-file.
312beacf11bSopenharmony_ci           */
313beacf11bSopenharmony_ci
314beacf11bSopenharmony_ci          if (--dev->d_nwriters <= 0)
315beacf11bSopenharmony_ci            {
316beacf11bSopenharmony_ci              while (sem_getvalue(&dev->d_rdsem, &sval) == 0 && sval == 0)
317beacf11bSopenharmony_ci                {
318beacf11bSopenharmony_ci                  sem_post(&dev->d_rdsem);
319beacf11bSopenharmony_ci                }
320beacf11bSopenharmony_ci
321beacf11bSopenharmony_ci              /* Inform poll readers that other end closed. */
322beacf11bSopenharmony_ci
323beacf11bSopenharmony_ci              pipecommon_pollnotify(dev, POLLHUP);
324beacf11bSopenharmony_ci            }
325beacf11bSopenharmony_ci        }
326beacf11bSopenharmony_ci
327beacf11bSopenharmony_ci      /* If opened for reading, decrement the count of readers on the pipe
328beacf11bSopenharmony_ci       * instance.
329beacf11bSopenharmony_ci       */
330beacf11bSopenharmony_ci
331beacf11bSopenharmony_ci      if ((filep->f_oflags & O_WRONLY) == 0)
332beacf11bSopenharmony_ci        {
333beacf11bSopenharmony_ci          if (--dev->d_nreaders <= 0)
334beacf11bSopenharmony_ci            {
335beacf11bSopenharmony_ci              if (PIPE_IS_POLICY_0(dev->d_flags))
336beacf11bSopenharmony_ci                {
337beacf11bSopenharmony_ci                  /* Inform poll writers that other end closed. */
338beacf11bSopenharmony_ci
339beacf11bSopenharmony_ci                  pipecommon_pollnotify(dev, POLLERR);
340beacf11bSopenharmony_ci                }
341beacf11bSopenharmony_ci            }
342beacf11bSopenharmony_ci        }
343beacf11bSopenharmony_ci    }
344beacf11bSopenharmony_ci
345beacf11bSopenharmony_ci  /* What is the buffer management policy?  Do we free the buffer when the
346beacf11bSopenharmony_ci   * last client closes the pipe policy 0, or when the buffer becomes empty.
347beacf11bSopenharmony_ci   * In the latter case, the buffer data will remain valid and can be
348beacf11bSopenharmony_ci   * obtained when the pipe is re-opened.
349beacf11bSopenharmony_ci   */
350beacf11bSopenharmony_ci
351beacf11bSopenharmony_ci  else if (PIPE_IS_POLICY_0(dev->d_flags) || dev->d_wrndx == dev->d_rdndx)
352beacf11bSopenharmony_ci    {
353beacf11bSopenharmony_ci      /* Policy 0 or the buffer is empty ... deallocate the buffer now. */
354beacf11bSopenharmony_ci
355beacf11bSopenharmony_ci      free(dev->d_buffer);
356beacf11bSopenharmony_ci      dev->d_buffer = NULL;
357beacf11bSopenharmony_ci
358beacf11bSopenharmony_ci      /* And reset all counts and indices */
359beacf11bSopenharmony_ci
360beacf11bSopenharmony_ci      dev->d_wrndx    = 0;
361beacf11bSopenharmony_ci      dev->d_rdndx    = 0;
362beacf11bSopenharmony_ci      dev->d_nwriters = 0;
363beacf11bSopenharmony_ci      dev->d_nreaders = 0;
364beacf11bSopenharmony_ci    }
365beacf11bSopenharmony_ci  VnodeHold();
366beacf11bSopenharmony_ci  vnode->useCount--;
367beacf11bSopenharmony_ci  VnodeDrop();
368beacf11bSopenharmony_ci  sem_post(&dev->d_bfsem);
369beacf11bSopenharmony_ci  return OK;
370beacf11bSopenharmony_ci}
371beacf11bSopenharmony_ci
372beacf11bSopenharmony_ci/****************************************************************************
373beacf11bSopenharmony_ci * Name: pipecommon_read
374beacf11bSopenharmony_ci ****************************************************************************/
375beacf11bSopenharmony_ci
376beacf11bSopenharmony_cissize_t pipecommon_read(struct file *filep, char *buffer, size_t len)
377beacf11bSopenharmony_ci{
378beacf11bSopenharmony_ci  struct Vnode      *vnode  = filep->f_vnode;
379beacf11bSopenharmony_ci  struct pipe_dev_s *dev    = (struct pipe_dev_s *)((struct drv_data *)vnode->data)->priv;
380beacf11bSopenharmony_ci  ssize_t                nread;
381beacf11bSopenharmony_ci  int                    sval;
382beacf11bSopenharmony_ci  int                    ret;
383beacf11bSopenharmony_ci  volatile int           num;
384beacf11bSopenharmony_ci
385beacf11bSopenharmony_ci  if (dev == NULL)
386beacf11bSopenharmony_ci    {
387beacf11bSopenharmony_ci      return -EINVAL;
388beacf11bSopenharmony_ci    }
389beacf11bSopenharmony_ci
390beacf11bSopenharmony_ci  if (len == 0)
391beacf11bSopenharmony_ci    {
392beacf11bSopenharmony_ci      return 0;
393beacf11bSopenharmony_ci    }
394beacf11bSopenharmony_ci
395beacf11bSopenharmony_ci  if (len > MAX_READ_WRITE_LEN)
396beacf11bSopenharmony_ci    {
397beacf11bSopenharmony_ci      return -EINVAL;
398beacf11bSopenharmony_ci    }
399beacf11bSopenharmony_ci
400beacf11bSopenharmony_ci  /* Make sure that we have exclusive access to the device structure */
401beacf11bSopenharmony_ci
402beacf11bSopenharmony_ci  ret = sem_wait(&dev->d_bfsem);
403beacf11bSopenharmony_ci  if (ret < 0)
404beacf11bSopenharmony_ci    {
405beacf11bSopenharmony_ci      return ret;
406beacf11bSopenharmony_ci    }
407beacf11bSopenharmony_ci
408beacf11bSopenharmony_ci  /* If the pipe is empty, then wait for something to be written to it */
409beacf11bSopenharmony_ci
410beacf11bSopenharmony_ci  while (dev->d_wrndx == dev->d_rdndx)
411beacf11bSopenharmony_ci    {
412beacf11bSopenharmony_ci      /* If O_NONBLOCK was set, then return EGAIN */
413beacf11bSopenharmony_ci
414beacf11bSopenharmony_ci      if (filep->f_oflags & O_NONBLOCK)
415beacf11bSopenharmony_ci        {
416beacf11bSopenharmony_ci          sem_post(&dev->d_bfsem);
417beacf11bSopenharmony_ci          return -EAGAIN;
418beacf11bSopenharmony_ci        }
419beacf11bSopenharmony_ci
420beacf11bSopenharmony_ci      /* If there are no writers on the pipe, then return end of file */
421beacf11bSopenharmony_ci
422beacf11bSopenharmony_ci      if (dev->d_nwriters <= 0)
423beacf11bSopenharmony_ci        {
424beacf11bSopenharmony_ci          sem_post(&dev->d_bfsem);
425beacf11bSopenharmony_ci          return 0;
426beacf11bSopenharmony_ci        }
427beacf11bSopenharmony_ci
428beacf11bSopenharmony_ci      /* Otherwise, wait for something to be written to the pipe */
429beacf11bSopenharmony_ci
430beacf11bSopenharmony_ci      sem_post(&dev->d_bfsem);
431beacf11bSopenharmony_ci      ret = sem_wait(&dev->d_rdsem);
432beacf11bSopenharmony_ci
433beacf11bSopenharmony_ci      if (ret < 0 || (ret = sem_wait(&dev->d_bfsem)) < 0)
434beacf11bSopenharmony_ci        {
435beacf11bSopenharmony_ci          return ret;
436beacf11bSopenharmony_ci        }
437beacf11bSopenharmony_ci    }
438beacf11bSopenharmony_ci
439beacf11bSopenharmony_ci  /* Then return whatever is available in the pipe (which is at least one byte) */
440beacf11bSopenharmony_ci
441beacf11bSopenharmony_ci  nread = 0;
442beacf11bSopenharmony_ci  for (; ; )
443beacf11bSopenharmony_ci    {
444beacf11bSopenharmony_ci      while ((size_t)nread < len && dev->d_wrndx != dev->d_rdndx)
445beacf11bSopenharmony_ci        {
446beacf11bSopenharmony_ci          ret = LOS_ArchCopyToUser(buffer, dev->d_buffer + dev->d_rdndx, sizeof(char));
447beacf11bSopenharmony_ci          if (ret != 0)
448beacf11bSopenharmony_ci            {
449beacf11bSopenharmony_ci              sem_post(&dev->d_bfsem);
450beacf11bSopenharmony_ci              return -EFAULT;
451beacf11bSopenharmony_ci            }
452beacf11bSopenharmony_ci          buffer++;
453beacf11bSopenharmony_ci          if (++dev->d_rdndx >= dev->d_bufsize)
454beacf11bSopenharmony_ci            {
455beacf11bSopenharmony_ci              dev->d_rdndx = 0;
456beacf11bSopenharmony_ci            }
457beacf11bSopenharmony_ci
458beacf11bSopenharmony_ci          nread++;
459beacf11bSopenharmony_ci        }
460beacf11bSopenharmony_ci
461beacf11bSopenharmony_ci      /* Is the read complete? */
462beacf11bSopenharmony_ci      if ((size_t)nread >= len)
463beacf11bSopenharmony_ci        {
464beacf11bSopenharmony_ci          break;
465beacf11bSopenharmony_ci        }
466beacf11bSopenharmony_ci
467beacf11bSopenharmony_ci      /* Notify all waiting writers that bytes have been read from the buffer */
468beacf11bSopenharmony_ci
469beacf11bSopenharmony_ci      num = 0;
470beacf11bSopenharmony_ci      while (sem_getvalue(&dev->d_wrsem, &sval) == 0 && sval == 0)
471beacf11bSopenharmony_ci        {
472beacf11bSopenharmony_ci          sem_post(&dev->d_wrsem);
473beacf11bSopenharmony_ci          num++;
474beacf11bSopenharmony_ci        }
475beacf11bSopenharmony_ci
476beacf11bSopenharmony_ci      /* If there are no writers be awakened, then return */
477beacf11bSopenharmony_ci
478beacf11bSopenharmony_ci      if (num == 0 || num == 1)
479beacf11bSopenharmony_ci        {
480beacf11bSopenharmony_ci          pipecommon_pollnotify(dev, POLLOUT);
481beacf11bSopenharmony_ci          sem_post(&dev->d_bfsem);
482beacf11bSopenharmony_ci          return nread;
483beacf11bSopenharmony_ci        }
484beacf11bSopenharmony_ci
485beacf11bSopenharmony_ci      /* If there are no writers on the pipe, then return the number of read bytes */
486beacf11bSopenharmony_ci
487beacf11bSopenharmony_ci      if (dev->d_nwriters <= 0)
488beacf11bSopenharmony_ci        {
489beacf11bSopenharmony_ci          sem_post(&dev->d_wrsem);
490beacf11bSopenharmony_ci          pipecommon_pollnotify(dev, POLLOUT);
491beacf11bSopenharmony_ci          sem_post(&dev->d_bfsem);
492beacf11bSopenharmony_ci          return nread;
493beacf11bSopenharmony_ci        }
494beacf11bSopenharmony_ci
495beacf11bSopenharmony_ci      /* wait for something to be written to the pipe */
496beacf11bSopenharmony_ci      pipecommon_pollnotify(dev, POLLOUT);
497beacf11bSopenharmony_ci
498beacf11bSopenharmony_ci      while (sem_getvalue(&dev->d_rdsem, &sval) == 0 && sval != 0)
499beacf11bSopenharmony_ci        {
500beacf11bSopenharmony_ci          sem_wait(&dev->d_rdsem);
501beacf11bSopenharmony_ci        }
502beacf11bSopenharmony_ci
503beacf11bSopenharmony_ci      sem_post(&dev->d_bfsem);
504beacf11bSopenharmony_ci
505beacf11bSopenharmony_ci      ret = sem_wait(&dev->d_rdsem);
506beacf11bSopenharmony_ci      if (ret < 0)
507beacf11bSopenharmony_ci        {
508beacf11bSopenharmony_ci          return ret;
509beacf11bSopenharmony_ci        }
510beacf11bSopenharmony_ci
511beacf11bSopenharmony_ci      ret = sem_wait(&dev->d_bfsem);
512beacf11bSopenharmony_ci      if (ret < 0)
513beacf11bSopenharmony_ci        {
514beacf11bSopenharmony_ci          return ret;
515beacf11bSopenharmony_ci        }
516beacf11bSopenharmony_ci    }
517beacf11bSopenharmony_ci
518beacf11bSopenharmony_ci  /* Notify all waiting writers that bytes have been removed from the buffer */
519beacf11bSopenharmony_ci
520beacf11bSopenharmony_ci  while (sem_getvalue(&dev->d_wrsem, &sval) == 0 && sval == 0)
521beacf11bSopenharmony_ci    {
522beacf11bSopenharmony_ci      sem_post(&dev->d_wrsem);
523beacf11bSopenharmony_ci    }
524beacf11bSopenharmony_ci
525beacf11bSopenharmony_ci  /* Notify all poll/select waiters that they can write to the FIFO */
526beacf11bSopenharmony_ci
527beacf11bSopenharmony_ci  pipecommon_pollnotify(dev, POLLOUT);
528beacf11bSopenharmony_ci  sem_post(&dev->d_bfsem);
529beacf11bSopenharmony_ci  return nread;
530beacf11bSopenharmony_ci}
531beacf11bSopenharmony_ci
532beacf11bSopenharmony_ci/****************************************************************************
533beacf11bSopenharmony_ci * Name: pipecommon_write
534beacf11bSopenharmony_ci ****************************************************************************/
535beacf11bSopenharmony_ci
536beacf11bSopenharmony_cissize_t pipecommon_write(struct file *filep, const char *buffer,
537beacf11bSopenharmony_ci                         size_t len)
538beacf11bSopenharmony_ci{
539beacf11bSopenharmony_ci  struct Vnode      *vnode    = filep->f_vnode;
540beacf11bSopenharmony_ci  struct pipe_dev_s *dev      = (struct pipe_dev_s *)((struct drv_data *)vnode->data)->priv;
541beacf11bSopenharmony_ci  ssize_t                nwritten = 0;
542beacf11bSopenharmony_ci  ssize_t                last;
543beacf11bSopenharmony_ci  int                    nxtwrndx;
544beacf11bSopenharmony_ci  int                    sval;
545beacf11bSopenharmony_ci  int                    ret;
546beacf11bSopenharmony_ci
547beacf11bSopenharmony_ci
548beacf11bSopenharmony_ci  if (dev == NULL)
549beacf11bSopenharmony_ci    {
550beacf11bSopenharmony_ci      return -EINVAL;
551beacf11bSopenharmony_ci    }
552beacf11bSopenharmony_ci
553beacf11bSopenharmony_ci  /* Handle zero-length writes */
554beacf11bSopenharmony_ci
555beacf11bSopenharmony_ci  if (len == 0)
556beacf11bSopenharmony_ci    {
557beacf11bSopenharmony_ci      return 0;
558beacf11bSopenharmony_ci    }
559beacf11bSopenharmony_ci
560beacf11bSopenharmony_ci  if (len > MAX_READ_WRITE_LEN)
561beacf11bSopenharmony_ci    {
562beacf11bSopenharmony_ci      return -EINVAL;
563beacf11bSopenharmony_ci    }
564beacf11bSopenharmony_ci
565beacf11bSopenharmony_ci  /* REVISIT:  "If all file descriptors referring to the read end of a pipe
566beacf11bSopenharmony_ci   * have been closed, then a write will cause a SIGPIPE signal to be
567beacf11bSopenharmony_ci   * generated for the calling process.  If the calling process is ignoring
568beacf11bSopenharmony_ci   * this signal, then write(2) fails with the error EPIPE."
569beacf11bSopenharmony_ci   */
570beacf11bSopenharmony_ci
571beacf11bSopenharmony_ci  if (dev->d_nreaders <= 0)
572beacf11bSopenharmony_ci    {
573beacf11bSopenharmony_ci      return -EPIPE;
574beacf11bSopenharmony_ci    }
575beacf11bSopenharmony_ci
576beacf11bSopenharmony_ci  /* At present, this method cannot be called from interrupt handlers.  That
577beacf11bSopenharmony_ci   * is because it calls sem_wait (via pipecommon_semtake below) and
578beacf11bSopenharmony_ci   * sem_wait cannot be called from interrupt level.  This actually
579beacf11bSopenharmony_ci   * happens fairly commonly IF [a-z]err() is called from interrupt handlers
580beacf11bSopenharmony_ci   * and stdout is being redirected via a pipe.  In that case, the debug
581beacf11bSopenharmony_ci   * output will try to go out the pipe (interrupt handlers should use the
582beacf11bSopenharmony_ci   * _err() APIs).
583beacf11bSopenharmony_ci   *
584beacf11bSopenharmony_ci   * On the other hand, it would be very valuable to be able to feed the pipe
585beacf11bSopenharmony_ci   * from an interrupt handler!  TODO:  Consider disabling interrupts instead
586beacf11bSopenharmony_ci   * of taking semaphores so that pipes can be written from interrupt handlers
587beacf11bSopenharmony_ci   */
588beacf11bSopenharmony_ci
589beacf11bSopenharmony_ci  /* Make sure that we have exclusive access to the device structure */
590beacf11bSopenharmony_ci
591beacf11bSopenharmony_ci  ret = sem_wait(&dev->d_bfsem);
592beacf11bSopenharmony_ci  if (ret < 0)
593beacf11bSopenharmony_ci    {
594beacf11bSopenharmony_ci      return ret;
595beacf11bSopenharmony_ci    }
596beacf11bSopenharmony_ci
597beacf11bSopenharmony_ci  /* Loop until all of the bytes have been written */
598beacf11bSopenharmony_ci
599beacf11bSopenharmony_ci  last = 0;
600beacf11bSopenharmony_ci  for (; ; )
601beacf11bSopenharmony_ci    {
602beacf11bSopenharmony_ci      /* Calculate the write index AFTER the next byte is written */
603beacf11bSopenharmony_ci
604beacf11bSopenharmony_ci      nxtwrndx = dev->d_wrndx + 1;
605beacf11bSopenharmony_ci      if (nxtwrndx >= dev->d_bufsize)
606beacf11bSopenharmony_ci        {
607beacf11bSopenharmony_ci          nxtwrndx = 0;
608beacf11bSopenharmony_ci        }
609beacf11bSopenharmony_ci
610beacf11bSopenharmony_ci      /* Would the next write overflow the circular buffer? */
611beacf11bSopenharmony_ci
612beacf11bSopenharmony_ci      if (nxtwrndx != dev->d_rdndx)
613beacf11bSopenharmony_ci        {
614beacf11bSopenharmony_ci          /* No... copy the byte */
615beacf11bSopenharmony_ci
616beacf11bSopenharmony_ci
617beacf11bSopenharmony_ci          ret = LOS_ArchCopyFromUser(dev->d_buffer + dev->d_wrndx, buffer, sizeof(char));
618beacf11bSopenharmony_ci          if (ret != 0)
619beacf11bSopenharmony_ci            {
620beacf11bSopenharmony_ci              sem_post(&dev->d_bfsem);
621beacf11bSopenharmony_ci              return -EFAULT;
622beacf11bSopenharmony_ci            }
623beacf11bSopenharmony_ci          buffer++;
624beacf11bSopenharmony_ci          dev->d_wrndx = nxtwrndx;
625beacf11bSopenharmony_ci
626beacf11bSopenharmony_ci          /* Is the write complete? */
627beacf11bSopenharmony_ci
628beacf11bSopenharmony_ci          nwritten++;
629beacf11bSopenharmony_ci          if ((size_t)nwritten >= len)
630beacf11bSopenharmony_ci            {
631beacf11bSopenharmony_ci              /* Yes.. Notify all of the waiting readers that more data is available */
632beacf11bSopenharmony_ci              while (sem_getvalue(&dev->d_rdsem, &sval) == 0 && sval == 0)
633beacf11bSopenharmony_ci                {
634beacf11bSopenharmony_ci                  sem_post(&dev->d_rdsem);
635beacf11bSopenharmony_ci                }
636beacf11bSopenharmony_ci
637beacf11bSopenharmony_ci              /* Notify all poll/select waiters that they can read from the FIFO */
638beacf11bSopenharmony_ci
639beacf11bSopenharmony_ci              pipecommon_pollnotify(dev, POLLIN);
640beacf11bSopenharmony_ci
641beacf11bSopenharmony_ci              /* Return the number of bytes written */
642beacf11bSopenharmony_ci
643beacf11bSopenharmony_ci              sem_post(&dev->d_bfsem);
644beacf11bSopenharmony_ci              return len;
645beacf11bSopenharmony_ci            }
646beacf11bSopenharmony_ci        }
647beacf11bSopenharmony_ci      else
648beacf11bSopenharmony_ci        {
649beacf11bSopenharmony_ci          /* There is not enough room for the next byte.  Was anything written in this pass? */
650beacf11bSopenharmony_ci
651beacf11bSopenharmony_ci          if (last < nwritten)
652beacf11bSopenharmony_ci            {
653beacf11bSopenharmony_ci              /* Yes.. Notify all of the waiting readers that more data is available */
654beacf11bSopenharmony_ci
655beacf11bSopenharmony_ci              while (sem_getvalue(&dev->d_rdsem, &sval) == 0 && sval == 0)
656beacf11bSopenharmony_ci                {
657beacf11bSopenharmony_ci                  sem_post(&dev->d_rdsem);
658beacf11bSopenharmony_ci                }
659beacf11bSopenharmony_ci
660beacf11bSopenharmony_ci              /* Notify all poll/select waiters that they can read from the FIFO */
661beacf11bSopenharmony_ci
662beacf11bSopenharmony_ci              pipecommon_pollnotify(dev, POLLIN);
663beacf11bSopenharmony_ci            }
664beacf11bSopenharmony_ci
665beacf11bSopenharmony_ci          last = nwritten;
666beacf11bSopenharmony_ci
667beacf11bSopenharmony_ci          /* If O_NONBLOCK was set, then return partial bytes written or EGAIN */
668beacf11bSopenharmony_ci
669beacf11bSopenharmony_ci          if (filep->f_oflags & O_NONBLOCK)
670beacf11bSopenharmony_ci            {
671beacf11bSopenharmony_ci              if (nwritten == 0)
672beacf11bSopenharmony_ci                {
673beacf11bSopenharmony_ci                  nwritten = -EAGAIN;
674beacf11bSopenharmony_ci                }
675beacf11bSopenharmony_ci
676beacf11bSopenharmony_ci              sem_post(&dev->d_bfsem);
677beacf11bSopenharmony_ci              return nwritten;
678beacf11bSopenharmony_ci            }
679beacf11bSopenharmony_ci
680beacf11bSopenharmony_ci          /* There is more to be written.. wait for data to be removed from the pipe */
681beacf11bSopenharmony_ci
682beacf11bSopenharmony_ci          while (sem_getvalue(&dev->d_wrsem, &sval) == 0 && sval != 0)
683beacf11bSopenharmony_ci            {
684beacf11bSopenharmony_ci              pipecommon_semtake(&dev->d_wrsem);
685beacf11bSopenharmony_ci            }
686beacf11bSopenharmony_ci          sem_post(&dev->d_bfsem);
687beacf11bSopenharmony_ci
688beacf11bSopenharmony_ci          pipecommon_semtake(&dev->d_wrsem);
689beacf11bSopenharmony_ci          pipecommon_semtake(&dev->d_bfsem);
690beacf11bSopenharmony_ci        }
691beacf11bSopenharmony_ci    }
692beacf11bSopenharmony_ci}
693beacf11bSopenharmony_ci
694beacf11bSopenharmony_ci/****************************************************************************
695beacf11bSopenharmony_ci * Name: pipecommon_poll
696beacf11bSopenharmony_ci ****************************************************************************/
697beacf11bSopenharmony_ci
698beacf11bSopenharmony_ciint pipecommon_poll(struct file *filep, poll_table *table)
699beacf11bSopenharmony_ci{
700beacf11bSopenharmony_ci  struct Vnode      *vnode    = filep->f_vnode;
701beacf11bSopenharmony_ci  struct pipe_dev_s *dev      = (struct pipe_dev_s *)((struct drv_data *)vnode->data)->priv;
702beacf11bSopenharmony_ci  pollevent_t            eventset;
703beacf11bSopenharmony_ci  pipe_ndx_t             nbytes;
704beacf11bSopenharmony_ci  int                    ret;
705beacf11bSopenharmony_ci
706beacf11bSopenharmony_ci  if (dev == NULL || table == NULL)
707beacf11bSopenharmony_ci    {
708beacf11bSopenharmony_ci      return -EINVAL;
709beacf11bSopenharmony_ci    }
710beacf11bSopenharmony_ci
711beacf11bSopenharmony_ci  /* Are we setting up the poll?  Or tearing it down? */
712beacf11bSopenharmony_ci
713beacf11bSopenharmony_ci  pipecommon_semtake(&dev->d_bfsem);
714beacf11bSopenharmony_ci
715beacf11bSopenharmony_ci  /* Should immediately notify on any of the requested events?
716beacf11bSopenharmony_ci   * First, determine how many bytes are in the buffer
717beacf11bSopenharmony_ci   */
718beacf11bSopenharmony_ci
719beacf11bSopenharmony_ci  if (dev->d_wrndx >= dev->d_rdndx)
720beacf11bSopenharmony_ci    {
721beacf11bSopenharmony_ci      nbytes = dev->d_wrndx - dev->d_rdndx;
722beacf11bSopenharmony_ci    }
723beacf11bSopenharmony_ci  else
724beacf11bSopenharmony_ci    {
725beacf11bSopenharmony_ci      nbytes = dev->d_bufsize + dev->d_wrndx - dev->d_rdndx;
726beacf11bSopenharmony_ci    }
727beacf11bSopenharmony_ci
728beacf11bSopenharmony_ci  /* Notify the POLLOUT event if the pipe is not full, but only if
729beacf11bSopenharmony_ci   * there is readers.
730beacf11bSopenharmony_ci   */
731beacf11bSopenharmony_ci
732beacf11bSopenharmony_ci  eventset = 0;
733beacf11bSopenharmony_ci  if (((filep->f_oflags & O_WRONLY) != 0) && (nbytes < (dev->d_bufsize - 1)))
734beacf11bSopenharmony_ci    {
735beacf11bSopenharmony_ci      eventset |= POLLOUT;
736beacf11bSopenharmony_ci    }
737beacf11bSopenharmony_ci
738beacf11bSopenharmony_ci  /* Notify the POLLIN event if the pipe is not empty */
739beacf11bSopenharmony_ci
740beacf11bSopenharmony_ci  if (((filep->f_oflags & O_WRONLY) == 0) && (nbytes > 0))
741beacf11bSopenharmony_ci    {
742beacf11bSopenharmony_ci      eventset |= POLLIN;
743beacf11bSopenharmony_ci    }
744beacf11bSopenharmony_ci
745beacf11bSopenharmony_ci  /* Notify the POLLHUP event if the pipe is empty and no writers */
746beacf11bSopenharmony_ci
747beacf11bSopenharmony_ci  if (nbytes == 0 && dev->d_nwriters <= 0)
748beacf11bSopenharmony_ci    {
749beacf11bSopenharmony_ci      eventset |= POLLHUP;
750beacf11bSopenharmony_ci    }
751beacf11bSopenharmony_ci
752beacf11bSopenharmony_ci  /* Change POLLOUT to POLLERR, if no readers and policy 0. */
753beacf11bSopenharmony_ci
754beacf11bSopenharmony_ci  if ((eventset | POLLOUT) &&
755beacf11bSopenharmony_ci      PIPE_IS_POLICY_0(dev->d_flags) &&
756beacf11bSopenharmony_ci      dev->d_nreaders <= 0)
757beacf11bSopenharmony_ci    {
758beacf11bSopenharmony_ci      eventset |= POLLERR;
759beacf11bSopenharmony_ci    }
760beacf11bSopenharmony_ci
761beacf11bSopenharmony_ci  ret = eventset & table->key;
762beacf11bSopenharmony_ci  if (ret == 0)
763beacf11bSopenharmony_ci    {
764beacf11bSopenharmony_ci      poll_wait(NULL, &dev->wq, table);
765beacf11bSopenharmony_ci    }
766beacf11bSopenharmony_ci  sem_post(&dev->d_bfsem);
767beacf11bSopenharmony_ci
768beacf11bSopenharmony_ci  return ret;
769beacf11bSopenharmony_ci}
770beacf11bSopenharmony_ci
771beacf11bSopenharmony_ci/****************************************************************************
772beacf11bSopenharmony_ci * Name: pipecommon_ioctl
773beacf11bSopenharmony_ci ****************************************************************************/
774beacf11bSopenharmony_ci
775beacf11bSopenharmony_ciint pipecommon_ioctl(struct file *filep, int cmd, unsigned long arg)
776beacf11bSopenharmony_ci{
777beacf11bSopenharmony_ci  return -ENOSYS;
778beacf11bSopenharmony_ci}
779beacf11bSopenharmony_ci
780beacf11bSopenharmony_ci/****************************************************************************
781beacf11bSopenharmony_ci * Name: pipecommon_unlink
782beacf11bSopenharmony_ci ****************************************************************************/
783beacf11bSopenharmony_ci
784beacf11bSopenharmony_ci#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
785beacf11bSopenharmony_ciint pipecommon_unlink(struct Vnode *vnode)
786beacf11bSopenharmony_ci{
787beacf11bSopenharmony_ci  struct pipe_dev_s *dev = NULL;
788beacf11bSopenharmony_ci
789beacf11bSopenharmony_ci  if (vnode == NULL || vnode->data == NULL)
790beacf11bSopenharmony_ci     {
791beacf11bSopenharmony_ci      return -EINVAL;
792beacf11bSopenharmony_ci     }
793beacf11bSopenharmony_ci
794beacf11bSopenharmony_ci  dev = ((struct drv_data *)vnode->data)->priv;
795beacf11bSopenharmony_ci  if (dev == NULL)
796beacf11bSopenharmony_ci    {
797beacf11bSopenharmony_ci      return -EINVAL;
798beacf11bSopenharmony_ci    }
799beacf11bSopenharmony_ci
800beacf11bSopenharmony_ci  if (dev->d_buffer)
801beacf11bSopenharmony_ci    {
802beacf11bSopenharmony_ci      free(dev->d_buffer);
803beacf11bSopenharmony_ci    }
804beacf11bSopenharmony_ci
805beacf11bSopenharmony_ci  /* And free the device structure. */
806beacf11bSopenharmony_ci  unregister_driver(dev->name);
807beacf11bSopenharmony_ci  pipecommon_freedev(dev);
808beacf11bSopenharmony_ci
809beacf11bSopenharmony_ci  return OK;
810beacf11bSopenharmony_ci}
811beacf11bSopenharmony_ci#endif
812beacf11bSopenharmony_ci
813beacf11bSopenharmony_ci#endif /* LOSCFG_KERNEL_PIPE */
814