FAR struct pipe_dev_s *pipecommon_allocdev(size_t bufsize) { FAR struct pipe_dev_s *dev; DEBUGASSERT(bufsize <= CONFIG_DEV_PIPE_MAXSIZE); /* Allocate a private structure to manage the pipe */ dev = (FAR struct pipe_dev_s *)kmm_malloc(sizeof(struct pipe_dev_s)); if (dev) { /* Initialize the private structure */ memset(dev, 0, sizeof(struct pipe_dev_s)); sem_init(&dev->d_bfsem, 0, 1); sem_init(&dev->d_rdsem, 0, 0); sem_init(&dev->d_wrsem, 0, 0); /* The read/write wait semaphores are used for signaling and, hence, * should not have priority inheritance enabled. */ sem_setprotocol(&dev->d_rdsem, SEM_PRIO_NONE); sem_setprotocol(&dev->d_wrsem, SEM_PRIO_NONE); dev->d_bufsize = bufsize; } return dev; }
FAR struct local_conn_s *local_alloc(void) { FAR struct local_conn_s *conn = (FAR struct local_conn_s *)kmm_zalloc(sizeof(struct local_conn_s)); if (conn) { /* Initialize non-zero elements the new connection structure */ conn->lc_infd = -1; conn->lc_outfd = -1; #ifdef CONFIG_NET_LOCAL_STREAM /* This semaphore is used for signaling and, hence, should not have * priority inheritance enabled. */ sem_init(&conn->lc_waitsem, 0, 0); sem_setprotocol(&conn->lc_waitsem, SEM_PRIO_NONE); #ifdef HAVE_LOCAL_POLL memset(conn->lc_accept_fds, 0, sizeof(conn->lc_accept_fds)); #endif #endif } return conn; }
int pwm_register(FAR const char *path, FAR struct pwm_lowerhalf_s *dev) { FAR struct pwm_upperhalf_s *upper; /* Allocate the upper-half data structure */ upper = (FAR struct pwm_upperhalf_s *)kmm_zalloc(sizeof(struct pwm_upperhalf_s)); if (!upper) { pwmerr("Allocation failed\n"); return -ENOMEM; } /* Initialize the PWM device structure (it was already zeroed by kmm_zalloc()) */ sem_init(&upper->exclsem, 0, 1); #ifdef CONFIG_PWM_PULSECOUNT sem_init(&upper->waitsem, 0, 0); /* The wait semaphore is used for signaling and, hence, should not have priority * inheritance enabled. */ sem_setprotocol(&upper->waitsem, SEM_PRIO_NONE); #endif upper->dev = dev; /* Register the PWM device */ pwminfo("Registering %s\n", path); return register_driver(path, &g_pwmops, 0666, upper); }
static ssize_t stm32l4_rngread(struct file *filep, char *buffer, size_t buflen) { if (sem_wait(&g_rngdev.rd_devsem) != OK) { return -errno; } else { /* We've got the device semaphore, proceed with reading */ /* Initialize the operation semaphore with 0 for blocking until the * buffer is filled from interrupts. The waitsem semaphore is used * for signaling and, hence, should not have priority inheritance * enabled. */ sem_init(&g_rngdev.rd_readsem, 0, 0); sem_setprotocol(&g_rngdev.rd_readsem, SEM_PRIO_NONE); g_rngdev.rd_buflen = buflen; g_rngdev.rd_buf = buffer; /* Enable RNG with interrupts */ stm32l4_rngenable(); /* Wait until the buffer is filled */ sem_wait(&g_rngdev.rd_readsem); /* Done with the operation semaphore */ sem_destroy(&g_rngdev.rd_readsem); /* Free RNG via the device semaphore for next use */ sem_post(&g_rngdev.rd_devsem); return buflen; } }
int max11802_register(FAR struct spi_dev_s *spi, FAR struct max11802_config_s *config, int minor) { FAR struct max11802_dev_s *priv; char devname[DEV_NAMELEN]; #ifdef CONFIG_MAX11802_MULTIPLE irqstate_t flags; #endif int ret; iinfo("spi: %p minor: %d\n", spi, minor); /* Debug-only sanity checks */ DEBUGASSERT(spi != NULL && config != NULL && minor >= 0 && minor < 100); /* Create and initialize a MAX11802 device driver instance */ #ifndef CONFIG_MAX11802_MULTIPLE priv = &g_max11802; #else priv = (FAR struct max11802_dev_s *)kmm_malloc(sizeof(struct max11802_dev_s)); if (!priv) { ierr("ERROR: kmm_malloc(%d) failed\n", sizeof(struct max11802_dev_s)); return -ENOMEM; } #endif /* Initialize the MAX11802 device driver instance */ memset(priv, 0, sizeof(struct max11802_dev_s)); priv->spi = spi; /* Save the SPI device handle */ priv->config = config; /* Save the board configuration */ priv->wdog = wd_create(); /* Create a watchdog timer */ priv->threshx = INVALID_THRESHOLD; /* Initialize thresholding logic */ priv->threshy = INVALID_THRESHOLD; /* Initialize thresholding logic */ /* Initialize semaphores */ sem_init(&priv->devsem, 0, 1); /* Initialize device structure semaphore */ sem_init(&priv->waitsem, 0, 0); /* Initialize pen event wait semaphore */ /* The pen event semaphore is used for signaling and, hence, should not * have priority inheritance enabled. */ sem_setprotocol(&priv->waitsem, SEM_PRIO_NONE); /* Make sure that interrupts are disabled */ config->clear(config); config->enable(config, false); /* Attach the interrupt handler */ ret = config->attach(config, max11802_interrupt); if (ret < 0) { ierr("ERROR: Failed to attach interrupt\n"); goto errout_with_priv; } iinfo("Mode: %d Bits: 8 Frequency: %d\n", CONFIG_MAX11802_SPIMODE, CONFIG_MAX11802_FREQUENCY); /* Lock the SPI bus so that we have exclusive access */ max11802_lock(spi); /* Configure MAX11802 registers */ SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, true); (void)SPI_SEND(priv->spi, MAX11802_CMD_MODE_WR); (void)SPI_SEND(priv->spi, MAX11802_MODE); SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, false); SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, true); (void)SPI_SEND(priv->spi, MAX11802_CMD_AVG_WR); (void)SPI_SEND(priv->spi, MAX11802_AVG); SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, false); SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, true); (void)SPI_SEND(priv->spi, MAX11802_CMD_TIMING_WR); (void)SPI_SEND(priv->spi, MAX11802_TIMING); SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, false); SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, true); (void)SPI_SEND(priv->spi, MAX11802_CMD_DELAY_WR); (void)SPI_SEND(priv->spi, MAX11802_DELAY); SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, false); /* Test that the device access was successful. */ SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, true); (void)SPI_SEND(priv->spi, MAX11802_CMD_MODE_RD); ret = SPI_SEND(priv->spi, 0); SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, false); /* Unlock the bus */ max11802_unlock(spi); if (ret != MAX11802_MODE) { ierr("ERROR: max11802 mode readback failed: %02x\n", ret); goto errout_with_priv; } /* Register the device as an input device */ (void)snprintf(devname, DEV_NAMELEN, DEV_FORMAT, minor); iinfo("Registering %s\n", devname); ret = register_driver(devname, &max11802_fops, 0666, priv); if (ret < 0) { ierr("ERROR: register_driver() failed: %d\n", ret); goto errout_with_priv; } /* If multiple MAX11802 devices are supported, then we will need to add * this new instance to a list of device instances so that it can be * found by the interrupt handler based on the recieved IRQ number. */ #ifdef CONFIG_MAX11802_MULTIPLE flags = enter_critical_section(); priv->flink = g_max11802list; g_max11802list = priv; leave_critical_section(flags); #endif /* Schedule work to perform the initial sampling and to set the data * availability conditions. */ ret = work_queue(HPWORK, &priv->work, max11802_worker, priv, 0); if (ret != 0) { ierr("ERROR: Failed to queue work: %d\n", ret); goto errout_with_priv; } /* And return success (?) */ return OK; errout_with_priv: sem_destroy(&priv->devsem); #ifdef CONFIG_MAX11802_MULTIPLE kmm_free(priv); #endif return ret; }
int usbmsc_configure(unsigned int nluns, void **handle) { FAR struct usbmsc_alloc_s *alloc; FAR struct usbmsc_dev_s *priv; FAR struct usbmsc_driver_s *drvr; int ret; #ifdef CONFIG_DEBUG if (nluns > 15) { usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_TOOMANYLUNS), 0); return -EDOM; } #endif /* Allocate the structures needed */ alloc = (FAR struct usbmsc_alloc_s *)kmm_malloc(sizeof(struct usbmsc_alloc_s)); if (!alloc) { usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_ALLOCDEVSTRUCT), 0); return -ENOMEM; } /* Initialize the USB storage driver structure */ priv = &alloc->dev; memset(priv, 0, sizeof(struct usbmsc_dev_s)); /* Initialize semaphores */ sem_init(&priv->thsynch, 0, 0); sem_init(&priv->thlock, 0, 1); sem_init(&priv->thwaitsem, 0, 0); /* * The thsynch and thwaitsem semaphores are used for signaling and, * hence, should not have priority inheritance enabled. */ sem_setprotocol(&priv->thsynch, SEM_PRIO_NONE); sem_setprotocol(&priv->thwaitsem, SEM_PRIO_NONE); sq_init(&priv->wrreqlist); priv->nluns = nluns; /* Allocate the LUN table */ priv->luntab = (FAR struct usbmsc_lun_s *) kmm_malloc(priv->nluns * sizeof(struct usbmsc_lun_s)); if (!priv->luntab) { ret = -ENOMEM; goto errout; } memset(priv->luntab, 0, priv->nluns * sizeof(struct usbmsc_lun_s)); /* Initialize the USB class driver structure */ drvr = &alloc->drvr; #ifdef CONFIG_USBDEV_DUALSPEED drvr->drvr.speed = USB_SPEED_HIGH; #else drvr->drvr.speed = USB_SPEED_FULL; #endif drvr->drvr.ops = &g_driverops; drvr->dev = priv; /* Return the handle and success */ *handle = (FAR void *)alloc; return OK; errout: usbmsc_uninitialize(alloc); return ret; }
static int icmpv6_send_message(FAR struct net_driver_s *dev, bool advertise) { struct icmpv6_router_s state; int ret; /* Initialize the state structure. This is done with interrupts * disabled */ /* This semaphore is used for signaling and, hence, should not have * priority inheritance enabled. */ (void)sem_init(&state.snd_sem, 0, 0); /* Doesn't really fail */ sem_setprotocol(&state.snd_sem, SEM_PRIO_NONE); #ifdef CONFIG_NETDEV_MULTINIC /* Remember the routing device name */ strncpy((FAR char *)state.snd_ifname, (FAR const char *)dev->d_ifname, IFNAMSIZ); #endif /* Allocate resources to receive a callback. This and the following * initialization is performed with the network lock because we don't * want anything to happen until we are ready. */ state.snd_cb = icmpv6_callback_alloc(dev); if (!state.snd_cb) { nerr("ERROR: Failed to allocate a cllback\n"); ret = -ENOMEM; goto errout_with_semaphore; } /* Arm the callback */ state.snd_sent = false; state.snd_result = -EBUSY; state.snd_advertise = advertise; state.snd_cb->flags = (ICMPv6_POLL | NETDEV_DOWN); state.snd_cb->priv = (FAR void *)&state; state.snd_cb->event = icmpv6_router_interrupt; /* Notify the device driver that new TX data is available. */ dev->d_txavail(dev); /* Wait for the send to complete or an error to occur: NOTES: (1) * net_lockedwait will also terminate if a signal is received, (2) * interrupts may be disabled! They will be re-enabled while the * task sleeps and automatically re-enabled when the task restarts. */ do { (void)net_lockedwait(&state.snd_sem); } while (!state.snd_sent); ret = state.snd_result; icmpv6_callback_free(dev, state.snd_cb); errout_with_semaphore: sem_destroy(&state.snd_sem); return ret; }
int slip_initialize(int intf, FAR const char *devname) { FAR struct slip_driver_s *priv; char buffer[8]; FAR char *argv[2]; /* Get the interface structure associated with this interface number. */ DEBUGASSERT(intf < CONFIG_NET_SLIP_NINTERFACES); priv = &g_slip[intf]; /* Initialize the driver structure */ memset(priv, 0, sizeof(struct slip_driver_s)); priv->dev.d_ifup = slip_ifup; /* I/F up (new IP address) callback */ priv->dev.d_ifdown = slip_ifdown; /* I/F down callback */ priv->dev.d_txavail = slip_txavail; /* New TX data callback */ #ifdef CONFIG_NET_IGMP priv->dev.d_addmac = slip_addmac; /* Add multicast MAC address */ priv->dev.d_rmmac = slip_rmmac; /* Remove multicast MAC address */ #endif priv->dev.d_private = priv; /* Used to recover private state from dev */ /* Open the device */ priv->fd = open(devname, O_RDWR, 0666); if (priv->fd < 0) { nerr("ERROR: Failed to open %s: %d\n", devname, errno); return -errno; } /* Initialize the wait semaphore */ sem_init(&priv->waitsem, 0, 0); sem_setprotocol(&priv->waitsem, SEM_PRIO_NONE); /* Put the interface in the down state. This usually amounts to resetting * the device and/or calling slip_ifdown(). */ slip_ifdown(&priv->dev); /* Start the SLIP receiver task */ snprintf(buffer, 8, "%d", intf); argv[0] = buffer; argv[1] = NULL; priv->rxpid = task_create("rxslip", CONFIG_NET_SLIP_DEFPRIO, CONFIG_NET_SLIP_STACKSIZE, (main_t)slip_rxtask, (FAR char * const *)argv); if (priv->rxpid < 0) { nerr("ERROR: Failed to start receiver task\n"); return -errno; } /* Wait and make sure that the receive task is started. */ slip_semtake(priv); /* Start the SLIP transmitter task */ priv->txpid = task_create("txslip", CONFIG_NET_SLIP_DEFPRIO, CONFIG_NET_SLIP_STACKSIZE, (main_t)slip_txtask, (FAR char * const *)argv); if (priv->txpid < 0) { nerr("ERROR: Failed to start receiver task\n"); return -errno; } /* Wait and make sure that the transmit task is started. */ slip_semtake(priv); /* Bump the semaphore count so that it can now be used as a mutex */ slip_semgive(priv); /* Register the device with the OS so that socket IOCTLs can be performed */ (void)netdev_register(&priv->dev, NET_LL_SLIP); /* When the RX and TX tasks were created, the TTY file descriptor was * dup'ed for each task. This task no longer needs the file descriptor * and we can safely close it. */ close(priv->fd); return OK; }
ssize_t psock_udp_sendto(FAR struct socket *psock, FAR const void *buf, size_t len, int flags, FAR const struct sockaddr *to, socklen_t tolen) { FAR struct udp_conn_s *conn; FAR struct net_driver_s *dev; struct sendto_s state; int ret; #if defined(CONFIG_NET_ARP_SEND) || defined(CONFIG_NET_ICMPv6_NEIGHBOR) #ifdef CONFIG_NET_ARP_SEND #ifdef CONFIG_NET_ICMPv6_NEIGHBOR if (psock->s_domain == PF_INET) #endif { FAR const struct sockaddr_in *into; /* Make sure that the IP address mapping is in the ARP table */ into = (FAR const struct sockaddr_in *)to; ret = arp_send(into->sin_addr.s_addr); } #endif /* CONFIG_NET_ARP_SEND */ #ifdef CONFIG_NET_ICMPv6_NEIGHBOR #ifdef CONFIG_NET_ARP_SEND else #endif { FAR const struct sockaddr_in6 *into; /* Make sure that the IP address mapping is in the Neighbor Table */ into = (FAR const struct sockaddr_in6 *)to; ret = icmpv6_neighbor(into->sin6_addr.s6_addr16); } #endif /* CONFIG_NET_ICMPv6_NEIGHBOR */ /* Did we successfully get the address mapping? */ if (ret < 0) { nerr("ERROR: Peer not reachable\n"); return -ENETUNREACH; } #endif /* CONFIG_NET_ARP_SEND || CONFIG_NET_ICMPv6_NEIGHBOR */ /* Set the socket state to sending */ psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND); /* Initialize the state structure. This is done with interrupts * disabled because we don't want anything to happen until we * are ready. */ net_lock(); memset(&state, 0, sizeof(struct sendto_s)); /* This semaphore is used for signaling and, hence, should not have * priority inheritance enabled. */ sem_init(&state.st_sem, 0, 0); sem_setprotocol(&state.st_sem, SEM_PRIO_NONE); state.st_buflen = len; state.st_buffer = buf; #if defined(CONFIG_NET_SENDTO_TIMEOUT) || defined(NEED_IPDOMAIN_SUPPORT) /* Save the reference to the socket structure if it will be needed for * asynchronous processing. */ state.st_sock = psock; #endif #ifdef CONFIG_NET_SENDTO_TIMEOUT /* Set the initial time for calculating timeouts */ state.st_time = clock_systimer(); #endif /* Setup the UDP socket. udp_connect will set the remote address in the * connection structure. */ conn = (FAR struct udp_conn_s *)psock->s_conn; DEBUGASSERT(conn); ret = udp_connect(conn, to); if (ret < 0) { nerr("ERROR: udp_connect failed: %d\n", ret); goto errout_with_lock; } /* Get the device that will handle the remote packet transfers. This * should never be NULL. */ dev = udp_find_raddr_device(conn); if (dev == NULL) { nerr("ERROR: udp_find_raddr_device failed\n"); ret = -ENETUNREACH; goto errout_with_lock; } /* Set up the callback in the connection */ state.st_cb = udp_callback_alloc(dev, conn); if (state.st_cb) { state.st_cb->flags = (UDP_POLL | NETDEV_DOWN); state.st_cb->priv = (FAR void *)&state; state.st_cb->event = sendto_interrupt; /* Notify the device driver of the availability of TX data */ netdev_txnotify_dev(dev); /* Wait for either the receive to complete or for an error/timeout to occur. * NOTES: (1) net_lockedwait will also terminate if a signal is received, (2) * interrupts may be disabled! They will be re-enabled while the task sleeps * and automatically re-enabled when the task restarts. */ net_lockedwait(&state.st_sem); /* Make sure that no further interrupts are processed */ udp_callback_free(dev, conn, state.st_cb); } /* The result of the sendto operation is the number of bytes transferred */ ret = state.st_sndlen; errout_with_lock: /* Release the semaphore */ sem_destroy(&state.st_sem); /* Set the socket state back to idle */ psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE); /* Unlock the network and return the result of the sendto() operation */ net_unlock(); return ret; }
int group_allocate(FAR struct task_tcb_s *tcb, uint8_t ttype) { FAR struct task_group_s *group; int ret; DEBUGASSERT(tcb && !tcb->cmn.group); /* Allocate the group structure and assign it to the TCB */ group = (FAR struct task_group_s *)kmm_zalloc(sizeof(struct task_group_s)); if (!group) { return -ENOMEM; } #if CONFIG_NFILE_STREAMS > 0 && (defined(CONFIG_BUILD_PROTECTED) || \ defined(CONFIG_BUILD_KERNEL)) && defined(CONFIG_MM_KERNEL_HEAP) /* If this group is being created for a privileged thread, then all elements * of the group must be created for privileged access. */ if ((ttype & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_KERNEL) { group->tg_flags |= GROUP_FLAG_PRIVILEGED; } /* In a flat, single-heap build. The stream list is allocated with the * group structure. But in a kernel build with a kernel allocator, it * must be separately allocated using a user-space allocator. */ group->tg_streamlist = (FAR struct streamlist *) group_zalloc(group, sizeof(struct streamlist)); if (!group->tg_streamlist) { kmm_free(group); return -ENOMEM; } #endif /* Attach the group to the TCB */ tcb->cmn.group = group; #if defined(HAVE_GROUP_MEMBERS) || defined(CONFIG_ARCH_ADDRENV) /* Assign the group a unique ID. If g_gidcounter were to wrap before we * finish with task creation, that would be a problem. */ group_assigngid(group); #endif /* Duplicate the parent tasks environment */ ret = env_dup(group); if (ret < 0) { #if CONFIG_NFILE_STREAMS > 0 && (defined(CONFIG_BUILD_PROTECTED) || \ defined(CONFIG_BUILD_KERNEL)) && defined(CONFIG_MM_KERNEL_HEAP) group_free(group, group->tg_streamlist); #endif kmm_free(group); tcb->cmn.group = NULL; return ret; } #ifndef CONFIG_DISABLE_PTHREAD /* Initialize the pthread join semaphore */ (void)sem_init(&group->tg_joinsem, 0, 1); #endif #if defined(CONFIG_SCHED_WAITPID) && !defined(CONFIG_SCHED_HAVE_PARENT) /* Initialize the exit/wait semaphores * * This semaphore is used for signaling and, hence, should not have * priority inheritance enabled. */ (void)sem_init(&group->tg_exitsem, 0, 0); (void)sem_setprotocol(&group->tg_exitsem, SEM_PRIO_NONE); #endif return OK; }
int pty_register(int minor) { FAR struct pty_devpair_s *devpair; int pipe_a[2]; int pipe_b[2]; char devname[16]; int ret; /* Allocate a device instance */ devpair = kmm_zalloc(sizeof(struct pty_devpair_s)); if (devpair == NULL) { return -ENOMEM; } /* Initialize semaphores */ sem_init(&devpair->pp_slavesem, 0, 0); sem_init(&devpair->pp_exclsem, 0, 1); /* The pp_slavesem semaphore is used for signaling and, hence, should not * have priority inheritance enabled. */ sem_setprotocol(&devpair->pp_slavesem, SEM_PRIO_NONE); #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS devpair->pp_minor = minor; #endif devpair->pp_locked = true; devpair->pp_master.pd_devpair = devpair; devpair->pp_master.pd_master = true; devpair->pp_slave.pd_devpair = devpair; /* Create two pipes: * * pipe_a: Master source, slave sink (TX, slave-to-master) * pipe_b: Master sink, slave source (RX, master-to-slave) */ ret = pipe2(pipe_a, CONFIG_PSEUDOTERM_TXBUFSIZE); if (ret < 0) { goto errout_with_devpair; } ret = pipe2(pipe_b, CONFIG_PSEUDOTERM_RXBUFSIZE); if (ret < 0) { goto errout_with_pipea; } /* Detach the pipe file descriptors (closing them in the process) * * fd[0] is for reading; * fd[1] is for writing. */ ret = file_detach(pipe_a[0], &devpair->pp_master.pd_src); if (ret < 0) { goto errout_with_pipeb; } pipe_a[0] = -1; ret = file_detach(pipe_a[1], &devpair->pp_slave.pd_sink); if (ret < 0) { goto errout_with_pipeb; } pipe_a[1] = -1; ret = file_detach(pipe_b[0], &devpair->pp_slave.pd_src); if (ret < 0) { goto errout_with_pipeb; } pipe_b[0] = -1; ret = file_detach(pipe_b[1], &devpair->pp_master.pd_sink); if (ret < 0) { goto errout_with_pipeb; } pipe_b[1] = -1; /* Register the slave device * * BSD style (deprecated): /dev/ttypN * SUSv1 style: /dev/pts/N * * Where N is the minor number */ #ifdef CONFIG_PSEUDOTERM_BSD snprintf(devname, 16, "/dev/ttyp%d", minor); #else snprintf(devname, 16, "/dev/pts/%d", minor); #endif ret = register_driver(devname, &g_pty_fops, 0666, &devpair->pp_slave); if (ret < 0) { goto errout_with_pipeb; } /* Register the master device * * BSD style (deprecated): /dev/ptyN * SUSv1 style: Master: /dev/ptmx (multiplexor, see ptmx.c) * * Where N is the minor number */ snprintf(devname, 16, "/dev/pty%d", minor); ret = register_driver(devname, &g_pty_fops, 0666, &devpair->pp_master); if (ret < 0) { goto errout_with_slave; } return OK; errout_with_slave: #ifdef CONFIG_PSEUDOTERM_BSD snprintf(devname, 16, "/dev/ttyp%d", minor); #else snprintf(devname, 16, "/dev/pts/%d", minor); #endif (void)unregister_driver(devname); errout_with_pipeb: if (pipe_b[0] >= 0) { close(pipe_b[0]); } else { (void)file_close_detached(&devpair->pp_master.pd_src); } if (pipe_b[1] >= 0) { close(pipe_b[1]); } else { (void)file_close_detached(&devpair->pp_slave.pd_sink); } errout_with_pipea: if (pipe_a[0] >= 0) { close(pipe_a[0]); } else { (void)file_close_detached(&devpair->pp_slave.pd_src); } if (pipe_a[1] >= 0) { close(pipe_a[1]); } else { (void)file_close_detached(&devpair->pp_master.pd_sink); } errout_with_devpair: sem_destroy(&devpair->pp_exclsem); sem_destroy(&devpair->pp_slavesem); kmm_free(devpair); return ret; }