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