1beacf11bSopenharmony_ci/****************************************************************************
2beacf11bSopenharmony_ci * drivers/pipes/pipe.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#include "pipe_common.h"
25beacf11bSopenharmony_ci#include <assert.h>
26beacf11bSopenharmony_ci#include <errno.h>
27beacf11bSopenharmony_ci#include <fcntl.h>
28beacf11bSopenharmony_ci#include <semaphore.h>
29beacf11bSopenharmony_ci#include <stdio.h>
30beacf11bSopenharmony_ci#include <sys/types.h>
31beacf11bSopenharmony_ci#include <unistd.h>
32beacf11bSopenharmony_ci#include "fs/driver.h"
33beacf11bSopenharmony_ci#include "los_init.h"
34beacf11bSopenharmony_ci
35beacf11bSopenharmony_ci#if CONFIG_DEV_PIPE_SIZE > 0
36beacf11bSopenharmony_ci
37beacf11bSopenharmony_ci/****************************************************************************
38beacf11bSopenharmony_ci * Pre-processor Definitions
39beacf11bSopenharmony_ci ****************************************************************************/
40beacf11bSopenharmony_ci
41beacf11bSopenharmony_ci#define MAX_PIPES 32
42beacf11bSopenharmony_ci
43beacf11bSopenharmony_ci/****************************************************************************
44beacf11bSopenharmony_ci * Private Types
45beacf11bSopenharmony_ci ****************************************************************************/
46beacf11bSopenharmony_ci
47beacf11bSopenharmony_ci/****************************************************************************
48beacf11bSopenharmony_ci * Private Function Prototypes
49beacf11bSopenharmony_ci ****************************************************************************/
50beacf11bSopenharmony_ci
51beacf11bSopenharmony_cistatic int pipe_close(struct file *filep);
52beacf11bSopenharmony_ci#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
53beacf11bSopenharmony_ciint pipe_unlink(struct Vnode *priv);
54beacf11bSopenharmony_ci#endif
55beacf11bSopenharmony_ci
56beacf11bSopenharmony_ci/****************************************************************************
57beacf11bSopenharmony_ci * Private Data
58beacf11bSopenharmony_ci ****************************************************************************/
59beacf11bSopenharmony_ci
60beacf11bSopenharmony_cistatic ssize_t pipe_map(struct file* filep, LosVmMapRegion *region)
61beacf11bSopenharmony_ci{
62beacf11bSopenharmony_ci  PRINTK("%s %d, mmap is not support\n", __FUNCTION__, __LINE__);
63beacf11bSopenharmony_ci  return 0;
64beacf11bSopenharmony_ci}
65beacf11bSopenharmony_ci
66beacf11bSopenharmony_cistatic const struct file_operations_vfs pipe_fops =
67beacf11bSopenharmony_ci{
68beacf11bSopenharmony_ci  .open = pipecommon_open,      /* open */
69beacf11bSopenharmony_ci  .close = pipe_close,          /* close */
70beacf11bSopenharmony_ci  .read = pipecommon_read,      /* read */
71beacf11bSopenharmony_ci  .write = pipecommon_write,    /* write */
72beacf11bSopenharmony_ci  .seek = NULL,                 /* seek */
73beacf11bSopenharmony_ci  .ioctl = NULL,                /* ioctl */
74beacf11bSopenharmony_ci  .mmap = pipe_map,             /* mmap */
75beacf11bSopenharmony_ci  .poll = pipecommon_poll,      /* poll */
76beacf11bSopenharmony_ci#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
77beacf11bSopenharmony_ci  .unlink = pipe_unlink,        /* unlink */
78beacf11bSopenharmony_ci#endif
79beacf11bSopenharmony_ci};
80beacf11bSopenharmony_ci
81beacf11bSopenharmony_cistatic sem_t  g_pipesem       = {NULL};
82beacf11bSopenharmony_cistatic uint32_t g_pipeset     = 0;
83beacf11bSopenharmony_cistatic uint32_t g_pipecreated = 0;
84beacf11bSopenharmony_ci
85beacf11bSopenharmony_ci/****************************************************************************
86beacf11bSopenharmony_ci * Private Functions
87beacf11bSopenharmony_ci ****************************************************************************/
88beacf11bSopenharmony_ci
89beacf11bSopenharmony_ci/****************************************************************************
90beacf11bSopenharmony_ci * Name: pipe_allocate
91beacf11bSopenharmony_ci ****************************************************************************/
92beacf11bSopenharmony_ci
93beacf11bSopenharmony_cistatic inline int pipe_allocate(void)
94beacf11bSopenharmony_ci{
95beacf11bSopenharmony_ci  int pipeno;
96beacf11bSopenharmony_ci  int ret = -ENFILE;
97beacf11bSopenharmony_ci
98beacf11bSopenharmony_ci  for (pipeno = 0; pipeno < MAX_PIPES; pipeno++)
99beacf11bSopenharmony_ci    {
100beacf11bSopenharmony_ci      if ((g_pipeset & (1 << pipeno)) == 0)
101beacf11bSopenharmony_ci        {
102beacf11bSopenharmony_ci          g_pipeset |= (1 << pipeno);
103beacf11bSopenharmony_ci          ret = pipeno;
104beacf11bSopenharmony_ci          break;
105beacf11bSopenharmony_ci        }
106beacf11bSopenharmony_ci    }
107beacf11bSopenharmony_ci
108beacf11bSopenharmony_ci  return ret;
109beacf11bSopenharmony_ci}
110beacf11bSopenharmony_ci
111beacf11bSopenharmony_ci/****************************************************************************
112beacf11bSopenharmony_ci * Name: pipe_free
113beacf11bSopenharmony_ci ****************************************************************************/
114beacf11bSopenharmony_ci
115beacf11bSopenharmony_cistatic inline void pipe_free(int pipeno)
116beacf11bSopenharmony_ci{
117beacf11bSopenharmony_ci  int ret;
118beacf11bSopenharmony_ci
119beacf11bSopenharmony_ci  ret = sem_wait(&g_pipesem);
120beacf11bSopenharmony_ci  if (ret == OK)
121beacf11bSopenharmony_ci    {
122beacf11bSopenharmony_ci      g_pipeset &= ~(1 << pipeno);
123beacf11bSopenharmony_ci      (void)sem_post(&g_pipesem);
124beacf11bSopenharmony_ci    }
125beacf11bSopenharmony_ci}
126beacf11bSopenharmony_ci
127beacf11bSopenharmony_ci/****************************************************************************
128beacf11bSopenharmony_ci * Name: pipe_close
129beacf11bSopenharmony_ci ****************************************************************************/
130beacf11bSopenharmony_ci
131beacf11bSopenharmony_cistatic int pipe_close(struct file *filep)
132beacf11bSopenharmony_ci{
133beacf11bSopenharmony_ci  struct Vnode *vnode    = filep->f_vnode;
134beacf11bSopenharmony_ci  struct pipe_dev_s *dev = (struct pipe_dev_s *)((struct drv_data *)vnode->data)->priv;
135beacf11bSopenharmony_ci  int ret;
136beacf11bSopenharmony_ci
137beacf11bSopenharmony_ci  if (dev == NULL)
138beacf11bSopenharmony_ci    {
139beacf11bSopenharmony_ci      return -EINVAL;
140beacf11bSopenharmony_ci    }
141beacf11bSopenharmony_ci
142beacf11bSopenharmony_ci  /* Perform common close operations */
143beacf11bSopenharmony_ci
144beacf11bSopenharmony_ci  ret = pipecommon_close(filep);
145beacf11bSopenharmony_ci  if (ret == 0 && vnode->useCount <= 1)
146beacf11bSopenharmony_ci    {
147beacf11bSopenharmony_ci      /* Release the pipe when there are no further open references to it. */
148beacf11bSopenharmony_ci
149beacf11bSopenharmony_ci      pipe_free(dev->d_pipeno);
150beacf11bSopenharmony_ci    }
151beacf11bSopenharmony_ci
152beacf11bSopenharmony_ci  return ret;
153beacf11bSopenharmony_ci}
154beacf11bSopenharmony_ci
155beacf11bSopenharmony_ci/****************************************************************************
156beacf11bSopenharmony_ci * Name: pipe_unlink
157beacf11bSopenharmony_ci ****************************************************************************/
158beacf11bSopenharmony_ci
159beacf11bSopenharmony_ci#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
160beacf11bSopenharmony_ci int pipe_unlink(struct Vnode *vnode)
161beacf11bSopenharmony_ci{
162beacf11bSopenharmony_ci  struct pipe_dev_s *dev = ((struct drv_data *)vnode->data)->priv;
163beacf11bSopenharmony_ci  uint8_t pipeno = 0;
164beacf11bSopenharmony_ci  int ret;
165beacf11bSopenharmony_ci
166beacf11bSopenharmony_ci  if (dev != NULL)
167beacf11bSopenharmony_ci    {
168beacf11bSopenharmony_ci        pipeno = dev->d_pipeno;
169beacf11bSopenharmony_ci    }
170beacf11bSopenharmony_ci  /* Perform common close operations */
171beacf11bSopenharmony_ci  ret = pipecommon_unlink(vnode);
172beacf11bSopenharmony_ci  if (ret == 0)
173beacf11bSopenharmony_ci    {
174beacf11bSopenharmony_ci      (void)sem_wait(&g_pipesem);
175beacf11bSopenharmony_ci      g_pipecreated &= ~(1 << pipeno);
176beacf11bSopenharmony_ci      (void)sem_post(&g_pipesem);
177beacf11bSopenharmony_ci      /* Release the pipe when there are no further open references to it. */
178beacf11bSopenharmony_ci      pipe_free(pipeno);
179beacf11bSopenharmony_ci    }
180beacf11bSopenharmony_ci  return ret;
181beacf11bSopenharmony_ci}
182beacf11bSopenharmony_ci#endif
183beacf11bSopenharmony_ci
184beacf11bSopenharmony_ci/****************************************************************************
185beacf11bSopenharmony_ci * Public Functions
186beacf11bSopenharmony_ci ****************************************************************************/
187beacf11bSopenharmony_ci
188beacf11bSopenharmony_ci/****************************************************************************
189beacf11bSopenharmony_ci * Name: pipe2
190beacf11bSopenharmony_ci *
191beacf11bSopenharmony_ci * Description:
192beacf11bSopenharmony_ci *   pipe() creates a pair of file descriptors, pointing to a pipe vnode,
193beacf11bSopenharmony_ci *   and  places them in the array pointed to by 'fd'. fd[0] is for reading,
194beacf11bSopenharmony_ci *   fd[1] is for writing.
195beacf11bSopenharmony_ci *
196beacf11bSopenharmony_ci *   NOTE: mkfifo2 is a special, non-standard, NuttX-only interface.  Since
197beacf11bSopenharmony_ci *   the NuttX FIFOs are based in in-memory, circular buffers, the ability
198beacf11bSopenharmony_ci *   to control the size of those buffers is critical for system tuning.
199beacf11bSopenharmony_ci *
200beacf11bSopenharmony_ci * Input Parameters:
201beacf11bSopenharmony_ci *   fd[2] - The user provided array in which to catch the pipe file
202beacf11bSopenharmony_ci *   descriptors
203beacf11bSopenharmony_ci *   bufsize - The size of the in-memory, circular buffer in bytes.
204beacf11bSopenharmony_ci *
205beacf11bSopenharmony_ci * Returned Value:
206beacf11bSopenharmony_ci *   0 is returned on success; otherwise, -1 is returned with errno set
207beacf11bSopenharmony_ci *   appropriately.
208beacf11bSopenharmony_ci *
209beacf11bSopenharmony_ci ****************************************************************************/
210beacf11bSopenharmony_ci
211beacf11bSopenharmony_cistatic void UpdateDev(struct pipe_dev_s *dev)
212beacf11bSopenharmony_ci{
213beacf11bSopenharmony_ci  int ret;
214beacf11bSopenharmony_ci  struct Vnode *vnode = NULL;
215beacf11bSopenharmony_ci  struct pipe_dev_s *olddev = NULL;
216beacf11bSopenharmony_ci  struct drv_data *data = NULL;
217beacf11bSopenharmony_ci
218beacf11bSopenharmony_ci  VnodeHold();
219beacf11bSopenharmony_ci  ret = VnodeLookup(dev->name, &vnode, 0);
220beacf11bSopenharmony_ci  if (ret != 0)
221beacf11bSopenharmony_ci    {
222beacf11bSopenharmony_ci      VnodeDrop();
223beacf11bSopenharmony_ci      PRINT_ERR("[%s,%d] failed. err: %d\n", __FUNCTION__, __LINE__, ret);
224beacf11bSopenharmony_ci      return;
225beacf11bSopenharmony_ci    }
226beacf11bSopenharmony_ci  data = (struct drv_data *)vnode->data;
227beacf11bSopenharmony_ci  olddev = (struct pipe_dev_s *)data->priv;
228beacf11bSopenharmony_ci  if (olddev != NULL)
229beacf11bSopenharmony_ci    {
230beacf11bSopenharmony_ci      if (olddev->d_buffer != NULL)
231beacf11bSopenharmony_ci        {
232beacf11bSopenharmony_ci          free(olddev->d_buffer);
233beacf11bSopenharmony_ci          olddev->d_buffer = NULL;
234beacf11bSopenharmony_ci        }
235beacf11bSopenharmony_ci      pipecommon_freedev(olddev);
236beacf11bSopenharmony_ci    }
237beacf11bSopenharmony_ci  data->priv = dev;
238beacf11bSopenharmony_ci  VnodeDrop();
239beacf11bSopenharmony_ci  return;
240beacf11bSopenharmony_ci}
241beacf11bSopenharmony_ci
242beacf11bSopenharmony_ciint pipe(int fd[2])
243beacf11bSopenharmony_ci{
244beacf11bSopenharmony_ci  struct pipe_dev_s *dev = NULL;
245beacf11bSopenharmony_ci  char devname[16];
246beacf11bSopenharmony_ci  int pipeno;
247beacf11bSopenharmony_ci  int errcode;
248beacf11bSopenharmony_ci  int ret;
249beacf11bSopenharmony_ci  struct file *filep = NULL;
250beacf11bSopenharmony_ci  size_t bufsize = 1024;
251beacf11bSopenharmony_ci
252beacf11bSopenharmony_ci  /* Get exclusive access to the pipe allocation data */
253beacf11bSopenharmony_ci
254beacf11bSopenharmony_ci  ret = sem_wait(&g_pipesem);
255beacf11bSopenharmony_ci  if (ret < 0)
256beacf11bSopenharmony_ci    {
257beacf11bSopenharmony_ci      errcode = -ret;
258beacf11bSopenharmony_ci      goto errout;
259beacf11bSopenharmony_ci    }
260beacf11bSopenharmony_ci
261beacf11bSopenharmony_ci  /* Allocate a minor number for the pipe device */
262beacf11bSopenharmony_ci
263beacf11bSopenharmony_ci  pipeno = pipe_allocate();
264beacf11bSopenharmony_ci  if (pipeno < 0)
265beacf11bSopenharmony_ci    {
266beacf11bSopenharmony_ci      (void)sem_post(&g_pipesem);
267beacf11bSopenharmony_ci      errcode = -pipeno;
268beacf11bSopenharmony_ci      goto errout;
269beacf11bSopenharmony_ci    }
270beacf11bSopenharmony_ci
271beacf11bSopenharmony_ci  /* Create a pathname to the pipe device */
272beacf11bSopenharmony_ci
273beacf11bSopenharmony_ci  snprintf_s(devname, sizeof(devname), sizeof(devname) - 1, "/dev/pipe%d", pipeno);
274beacf11bSopenharmony_ci
275beacf11bSopenharmony_ci  /* No.. Allocate and initialize a new device structure instance */
276beacf11bSopenharmony_ci
277beacf11bSopenharmony_ci  dev = pipecommon_allocdev(bufsize, devname);
278beacf11bSopenharmony_ci  if (!dev)
279beacf11bSopenharmony_ci    {
280beacf11bSopenharmony_ci      (void)sem_post(&g_pipesem);
281beacf11bSopenharmony_ci      errcode = ENOMEM;
282beacf11bSopenharmony_ci      goto errout_with_pipe;
283beacf11bSopenharmony_ci    }
284beacf11bSopenharmony_ci
285beacf11bSopenharmony_ci  dev->d_pipeno = pipeno;
286beacf11bSopenharmony_ci
287beacf11bSopenharmony_ci  /* Check if the pipe device has already been created */
288beacf11bSopenharmony_ci
289beacf11bSopenharmony_ci  if ((g_pipecreated & (1 << pipeno)) == 0)
290beacf11bSopenharmony_ci    {
291beacf11bSopenharmony_ci      /* Register the pipe device */
292beacf11bSopenharmony_ci
293beacf11bSopenharmony_ci      ret = register_driver(devname, &pipe_fops, 0660, (void *)dev);
294beacf11bSopenharmony_ci      if (ret != 0)
295beacf11bSopenharmony_ci        {
296beacf11bSopenharmony_ci          (void)sem_post(&g_pipesem);
297beacf11bSopenharmony_ci          errcode = -ret;
298beacf11bSopenharmony_ci          goto errout_with_dev;
299beacf11bSopenharmony_ci        }
300beacf11bSopenharmony_ci
301beacf11bSopenharmony_ci      /* Remember that we created this device */
302beacf11bSopenharmony_ci
303beacf11bSopenharmony_ci       g_pipecreated |= (1 << pipeno);
304beacf11bSopenharmony_ci    }
305beacf11bSopenharmony_ci  else
306beacf11bSopenharmony_ci    {
307beacf11bSopenharmony_ci       UpdateDev(dev);
308beacf11bSopenharmony_ci    }
309beacf11bSopenharmony_ci  (void)sem_post(&g_pipesem);
310beacf11bSopenharmony_ci
311beacf11bSopenharmony_ci  /* Get a write file descriptor */
312beacf11bSopenharmony_ci
313beacf11bSopenharmony_ci  fd[1] = open(devname, O_WRONLY);
314beacf11bSopenharmony_ci  if (fd[1] < 0)
315beacf11bSopenharmony_ci    {
316beacf11bSopenharmony_ci      errcode = -fd[1];
317beacf11bSopenharmony_ci      goto errout_with_driver;
318beacf11bSopenharmony_ci    }
319beacf11bSopenharmony_ci
320beacf11bSopenharmony_ci  /* Get a read file descriptor */
321beacf11bSopenharmony_ci
322beacf11bSopenharmony_ci  fd[0] = open(devname, O_RDONLY);
323beacf11bSopenharmony_ci  if (fd[0] < 0)
324beacf11bSopenharmony_ci    {
325beacf11bSopenharmony_ci      errcode = -fd[0];
326beacf11bSopenharmony_ci      goto errout_with_wrfd;
327beacf11bSopenharmony_ci    }
328beacf11bSopenharmony_ci
329beacf11bSopenharmony_ci  ret = fs_getfilep(fd[0], &filep);
330beacf11bSopenharmony_ci  filep->ops = &pipe_fops;
331beacf11bSopenharmony_ci
332beacf11bSopenharmony_ci  ret = fs_getfilep(fd[1], &filep);
333beacf11bSopenharmony_ci  filep->ops = &pipe_fops;
334beacf11bSopenharmony_ci
335beacf11bSopenharmony_ci  return OK;
336beacf11bSopenharmony_ci
337beacf11bSopenharmony_cierrout_with_wrfd:
338beacf11bSopenharmony_ci  close(fd[1]);
339beacf11bSopenharmony_ci
340beacf11bSopenharmony_cierrout_with_driver:
341beacf11bSopenharmony_ci  unregister_driver(devname);
342beacf11bSopenharmony_ci  (void)sem_wait(&g_pipesem);
343beacf11bSopenharmony_ci  g_pipecreated &= ~(1 << pipeno);
344beacf11bSopenharmony_ci  (void)sem_post(&g_pipesem);
345beacf11bSopenharmony_ci
346beacf11bSopenharmony_cierrout_with_dev:
347beacf11bSopenharmony_ci  if (dev)
348beacf11bSopenharmony_ci    {
349beacf11bSopenharmony_ci      pipecommon_freedev(dev);
350beacf11bSopenharmony_ci    }
351beacf11bSopenharmony_ci
352beacf11bSopenharmony_cierrout_with_pipe:
353beacf11bSopenharmony_ci  pipe_free(pipeno);
354beacf11bSopenharmony_ci
355beacf11bSopenharmony_cierrout:
356beacf11bSopenharmony_ci  set_errno(errcode);
357beacf11bSopenharmony_ci  return VFS_ERROR;
358beacf11bSopenharmony_ci}
359beacf11bSopenharmony_ci
360beacf11bSopenharmony_ciint pipe_init(void)
361beacf11bSopenharmony_ci{
362beacf11bSopenharmony_ci    int ret = sem_init(&g_pipesem, 0, 1);
363beacf11bSopenharmony_ci    if (ret != 0) {
364beacf11bSopenharmony_ci        dprintf("pipe_init failed!\n");
365beacf11bSopenharmony_ci    }
366beacf11bSopenharmony_ci    return ret;
367beacf11bSopenharmony_ci}
368beacf11bSopenharmony_ci
369beacf11bSopenharmony_ciLOS_MODULE_INIT(pipe_init, LOS_INIT_LEVEL_KMOD_EXTENDED);
370beacf11bSopenharmony_ci
371beacf11bSopenharmony_ci#endif /* CONFIG_DEV_PIPE_SIZE > 0 */
372