/*! \fn AhdlcRx(void *arg) * \brief Asynchronous HDLC receiver thread. * * * Running at high priority. */ THREAD(AhdlcRx, arg) { NUTDEVICE *dev = arg; NUTDEVICE *netdev; AHDLCDCB *dcb = dev->dev_dcb; IFNET *ifn; NETBUF *nb; uint8_t *rxbuf; uint8_t *rxptr; uint16_t rxcnt; uint8_t ch; uint16_t tbx; uint8_t inframe; uint8_t escaped; uint16_t rxfcs; NutThreadSetPriority(9); for (;;) { /* * Reset variables to their initial state */ rxptr = 0; rxcnt = 0; escaped = 0; rxfcs = AHDLC_INITFCS; inframe = 0; for (;;) { /* * Wait until the network interface has been attached. * This will be initiated by the application calling * NutNetIfConfig(), which in turn calls a HDLC_SETIFNET * ioctl() to store the NUTDEVICE pointer of the network * device in dev_icb and trigger an event on dcb_mf_evt. */ while ((netdev = dev->dev_icb) == 0) { if (NutEventWait(&dcb->dcb_mf_evt, 1000) == 0) { NutSleep(100); } } ifn = netdev->dev_icb; dcb->dcb_rtimeout = 1000; inframe = 0; /* * Allocate the receive buffer, if this fails, we are in a * low memory situation. Take a nap and see, if the * situation improved. */ if ((rxbuf = NutHeapAlloc(dcb->dcb_rx_mru)) != 0) { break; } NutSleep(1000); } /* * Signal the link driver that we are up. */ ifn->if_send = AhdlcOutput; netdev->dev_ioctl(netdev, LCP_LOWERUP, 0); for (;;) { /* * If we are still connected to a network, fetch the next * character from the buffer. */ while (dcb->dcb_rd_idx == dcb->dcb_rx_idx) { if (dev->dev_icb == 0) break; // TODO: Check for idle timeout. if (NutEventWait(&dcb->dcb_rx_rdy, dcb->dcb_rtimeout)) { continue; } } /* * Leave loop if network interface is detached */ if (dev->dev_icb == 0) break; /* * If RAW mode is active, we are not allowing any data encapsulation * processing. So we just sleep for a while. */ if (dcb->dcb_modeflags & UART_MF_RAWMODE) { /* * It is a must to sleep here, because if we just yield it could create * too much processing in here and stall processing elsewhere. This gives * opportunity to other threads to process incoming data from USART. */ NutSleep(100); continue; } /* * Read next character from input buffer */ ch = dcb->dcb_rx_buf[dcb->dcb_rd_idx++]; if (inframe) { if (ch != AHDLC_FLAG) { if (ch == AHDLC_ESCAPE) { escaped = 1; continue; } if (escaped) { ch ^= AHDLC_TRANS; escaped = 0; } /* * Unless the peer lied to us about the negotiated MRU, * we should never get a frame which is too long. If it * happens, toss it away and grab the next incoming one. */ if (rxcnt++ < dcb->dcb_rx_mru) { /* Update calculated checksum and store character in buffer. */ tbx = (uint16_t) ((uint8_t) rxfcs ^ ch) << 1; rxfcs >>= 8; rxfcs ^= ((uint16_t) PRG_RDB(fcstab + tbx) << 8) | PRG_RDB(fcstab + tbx + 1); *rxptr++ = ch; } else inframe = 0; continue; } if (rxcnt > 6 && rxfcs == AHDLC_GOODFCS) { /* * If the frame checksum is valid, create a NETBUF * and pass it to the network specific receive handler. */ rxcnt -= 2; if ((nb = NutNetBufAlloc(0, NBAF_DATALINK, rxcnt)) != 0) { memcpy(nb->nb_dl.vp, rxbuf, rxcnt); (*ifn->if_recv) (netdev, nb); } } } /* * If frame flag is received, resync frame processing */ if (ch == AHDLC_FLAG) { inframe = 1; escaped = 0; rxptr = rxbuf; rxcnt = 0; rxfcs = AHDLC_INITFCS; } }
/*! * \brief Mount a partition. * * Nut/OS doesn't provide specific routines for mounting. Instead routines * for opening files are used. * * Applications should not directly call this function, but use the high * level stdio routines for opening a file. * * \param dev Pointer to the MMC device. * \param name Partition number followed by a slash followed by a name * of the file system device. Both items are optional. If no * file system driver name is given, the first file system * driver found in the list of registered devices will be * used. If no partition number is specified or if partition * zero is given, the first active primary partition will be * used. * \param mode Opening mode. Currently ignored, but * \code _O_RDWR | _O_BINARY \endcode should be used for * compatibility with future enhancements. * \param acc File attributes, ignored. * * \return Pointer to a newly created file pointer to the mounted * partition or NUTFILE_EOF in case of any error. */ static NUTFILE *At91MciMount(NUTDEVICE * dev, CONST char *name, int mode, int acc) { int partno = 0; int i; NUTDEVICE *fsdev; NUTFILE *nfp; MCIFCB *fcb; DOSPART *part; MCIFC *ifc = (MCIFC *) dev->dev_icb; FSCP_VOL_MOUNT mparm; if (At91MciDiscover(ifc)) { errno = ENODEV; return NUTFILE_EOF; } /* Parse the name for a partition number and a file system driver. */ if (*name) { partno = atoi(name); do { name++; } while (*name && *name != '/'); if (*name == '/') { name++; } } #ifdef NUTDEBUG printf("['%s'-PART%d]", name, partno); #endif /* * Check the list of registered devices for the given name of the * files system driver. If none has been specified, get the first * file system driver in the list. Hopefully the application * registered one only. */ for (fsdev = nutDeviceList; fsdev; fsdev = fsdev->dev_next) { if (*name == 0) { if (fsdev->dev_type == IFTYP_FS) { break; } } else if (strcmp(fsdev->dev_name, name) == 0) { break; } } if (fsdev == 0) { #ifdef NUTDEBUG printf("[No FSDriver]"); #endif errno = ENODEV; return NUTFILE_EOF; } if ((fcb = NutHeapAllocClear(sizeof(MCIFCB))) == 0) { errno = ENOMEM; return NUTFILE_EOF; } fcb->fcb_fsdev = fsdev; /* Initialize MMC access mutex semaphore. */ NutEventPost(&mutex); /* Read MBR. */ if (At91MciReadSingle(ifc, 0, fcb->fcb_blkbuf)) { NutHeapFree(fcb); return NUTFILE_EOF; } /* Read partition table. */ part = (DOSPART *) & fcb->fcb_blkbuf[DOSPART_SECTORPOS]; for (i = 1; i <= 4; i++) { if (partno) { if (i == partno) { /* Found specified partition number. */ fcb->fcb_part = *part; break; } } else if (part->part_state & 0x80) { /* Located first active partition. */ fcb->fcb_part = *part; break; } part++; } if (fcb->fcb_part.part_type == PTYPE_EMPTY) { NutHeapFree(fcb); return NUTFILE_EOF; } if ((nfp = NutHeapAlloc(sizeof(NUTFILE))) == 0) { NutHeapFree(fcb); errno = ENOMEM; return NUTFILE_EOF; } nfp->nf_next = 0; nfp->nf_dev = dev; nfp->nf_fcb = fcb; /* * Mount the file system volume. */ mparm.fscp_bmnt = nfp; mparm.fscp_part_type = fcb->fcb_part.part_type; if (fsdev->dev_ioctl(fsdev, FS_VOL_MOUNT, &mparm)) { At91MciUnmount(nfp); return NUTFILE_EOF; } return nfp; }