diff --git a/device/x86-galileo/eth/colon2mac.c b/device/x86-galileo/eth/colon2mac.c new file mode 100644 index 0000000..ed2ab75 --- /dev/null +++ b/device/x86-galileo/eth/colon2mac.c @@ -0,0 +1,60 @@ +/* colon2mac.c - colon2mac */ + +#include +#include + +/*------------------------------------------------------------------------ + * colonmac - Parse a colon-hex Ethernet address and convert to binary + *------------------------------------------------------------------------ + */ +int32 colon2mac ( + char *src, /* Ptr to Ethernet address in ASCII of */ + /* the form: xx:xx:xx:xx:xx:xx */ + byte *dst /* Where to put binary form of address */ + ) +{ + int32 cnt; /* Count of output bytes */ + int32 digit = 0; /* Next digit in binary */ + int32 ch = 0; /* Next digit in ASCII */ + + /* Validate arguments */ + + if (src == NULL || dst == NULL) { + return SYSERR; + } + + /* For each of the six bytes in an Ethernet address */ + + for (cnt = 0; (cnt < ETH_ADDR_LEN) && (src != NULLCH); cnt++) { + + /* Get first hex character and convert to binary */ + + ch = *src++; + if (isdigit(ch)) { + digit = ch - '0'; + } else if (isxdigit(ch)) { + digit = 10 + ch - (isupper(ch) ? 'A' : 'a'); + } else { + digit = 0; + } + dst[cnt] = digit << 4; + + /* Get second hex character and convert to binary */ + + ch = *src++; + + if (isdigit(ch)) { + digit = ch - '0'; + } else if (isxdigit(ch)) { + digit = 10 + ch - (isupper(ch) ? 'A' : 'a'); + } else { + digit = 0; + } + dst[cnt] |= digit; + + if (*src++ != ':') { + break; + } + } + return cnt; +} diff --git a/device/x86-galileo/eth/ethcontrol.c b/device/x86-galileo/eth/ethcontrol.c new file mode 100644 index 0000000..ec0e795 --- /dev/null +++ b/device/x86-galileo/eth/ethcontrol.c @@ -0,0 +1,47 @@ +/* ethcontrol.c - ethcontrol */ + +#include + +/*------------------------------------------------------------------------ + * ethcontrol - implement control function for a quark ethernet device + *------------------------------------------------------------------------ + */ +devcall ethcontrol ( + struct dentry *devptr, /* entry in device switch table */ + int32 func, /* control function */ + int32 arg1, /* argument 1, if needed */ + int32 arg2 /* argument 2, if needed */ + ) +{ + struct ethcblk *ethptr; /* Ethertab entry pointer */ + int32 retval = OK; /* Return value of cntl function*/ + + ethptr = ðertab[devptr->dvminor]; + + switch (func) { + + /* Get MAC address */ + + case ETH_CTRL_GET_MAC: + memcpy((byte *)arg1, ethptr->devAddress, + ETH_ADDR_LEN); + break; + + /* Add a multicast address */ + + case ETH_CTRL_ADD_MCAST: + retval = ethmcast_add(ethptr, (byte *)arg1); + break; + + /* Remove a multicast address */ + + case ETH_CTRL_REMOVE_MCAST: + retval = ethmcast_remove(ethptr, (byte *)arg1); + break; + + default: + return SYSERR; + } + + return retval; +} diff --git a/device/x86-galileo/eth/ethdispatch.S b/device/x86-galileo/eth/ethdispatch.S new file mode 100644 index 0000000..ea4ead3 --- /dev/null +++ b/device/x86-galileo/eth/ethdispatch.S @@ -0,0 +1,20 @@ +/* ethdispatch.S - ethdispatch */ + +#include + .text + .globl ethdispatch + .globl ethhandler +ethdispatch: + pushal + pushfl + cli + movb $EOI,%al # clear the interrupt + outb %al,$OCW1_2 + movb $EOI,%al + outb %al,$OCW2_2 + + call ethhandler + + popfl + popal + iret diff --git a/device/x86-galileo/eth/ethhandler.c b/device/x86-galileo/eth/ethhandler.c new file mode 100644 index 0000000..415f7aa --- /dev/null +++ b/device/x86-galileo/eth/ethhandler.c @@ -0,0 +1,127 @@ +/* ethhandler.c - ethhandler */ + +#include + +/*------------------------------------------------------------------------ + * ethhandler - Interrupt handler for Intel Quark Ethernet + *------------------------------------------------------------------------ + */ +interrupt ethhandler(void) +{ + struct ethcblk *ethptr; /* Ethertab entry pointer */ + struct eth_q_csreg *csrptr; /* Pointer to Ethernet CRSs */ + struct eth_q_tx_desc *tdescptr;/* Pointer to tx descriptor */ + struct eth_q_rx_desc *rdescptr;/* Pointer to rx descriptor */ + volatile uint32 sr; /* Copy of status register */ + uint32 count; /* Variable used to count pkts */ + + ethptr = ðertab[devtab[ETHER0].dvminor]; + + csrptr = (struct eth_q_csreg *)ethptr->csr; + + /* Copy the status register into a local variable */ + + sr = csrptr->sr; + + /* If there is no interrupt pending, return */ + + if((csrptr->sr & ETH_QUARK_SR_NIS) == 0) { + return; + } + + /* Acknowledge the interrupt */ + + csrptr->sr = sr; + + /* Check status register to figure out the source of interrupt */ + + if (sr & ETH_QUARK_SR_TI) { /* Transmit interrupt */ + + /* Pointer to the head of transmit desc ring */ + + tdescptr = (struct eth_q_tx_desc *)ethptr->txRing + + ethptr->txHead; + + /* Start packet count at zero */ + + count = 0; + + /* Repeat until we process all the descriptor slots */ + + while(ethptr->txHead != ethptr->txTail) { + + /* If the descriptor is owned by DMA, stop here */ + + if(tdescptr->ctrlstat & ETH_QUARK_TDCS_OWN) { + break; + } + + /* Descriptor was processed; increment count */ + + count++; + + /* Go to the next descriptor */ + + tdescptr += 1; + + /* Increment the head of the transmit desc ring */ + + ethptr->txHead += 1; + if(ethptr->txHead >= ethptr->txRingSize) { + ethptr->txHead = 0; + tdescptr = (struct eth_q_tx_desc *) + ethptr->txRing; + } + } + + /* 'count' packets were processed by DMA, and slots are */ + /* now free; signal the semaphore accordingly */ + + signaln(ethptr->osem, count); + + } + if(sr & ETH_QUARK_SR_RI) { /* Receive interrupt */ + + /* Get the pointer to the tail of the receive desc list */ + + rdescptr = (struct eth_q_rx_desc *)ethptr->rxRing + + ethptr->rxTail; + + count = 0; /* Start packet count at zero */ + + /* Repeat until we have received */ + /* maximum no. packets that can fit in queue */ + + while(count <= ethptr->rxRingSize) { + + /* If the descriptor is owned by the DMA, stop */ + + if(rdescptr->status & ETH_QUARK_RDST_OWN) { + break; + } + + /* Descriptor was processed; increment count */ + count++; + + /* Go to the next descriptor */ + + rdescptr += 1; + + /* Increment the tail index of the rx desc ring */ + + ethptr->rxTail += 1; + if(ethptr->rxTail >= ethptr->rxRingSize) { + ethptr->rxTail = 0; + rdescptr = (struct eth_q_rx_desc *) + ethptr->rxRing; + } + } + + /* 'count' packets were received and are available, */ + /* so signal the semaphore accordingly */ + + signaln(ethptr->isem, count); + } + + return; +} diff --git a/device/x86-galileo/eth/ethinit.c b/device/x86-galileo/eth/ethinit.c new file mode 100644 index 0000000..0abd63f --- /dev/null +++ b/device/x86-galileo/eth/ethinit.c @@ -0,0 +1,320 @@ +/* ethinit.c - ethinit, eth_phy_read, eth_phy_write */ + +#include + +struct ethcblk ethertab[1]; + +/*------------------------------------------------------------------------ + * eth_phy_read - Read a PHY register + *------------------------------------------------------------------------ + */ +uint16 eth_phy_read ( + volatile struct eth_q_csreg *csrptr, /* CSR address */ + uint32 regnum /* Register */ + ) +{ + uint32 retries; /* No. of retries for read */ + + /* Wait for the MII to be ready */ + + while(csrptr->gmiiar & ETH_QUARK_GMIIAR_GB); + + /* Prepare the GMII address register for read transaction */ + + csrptr->gmiiar = + (1 << 11) | /* Physical Layer Address = 1 */ + (regnum << 6) | /* PHY Register Number */ + (ETH_QUARK_GMIIAR_CR) | /* GMII Clock Range 100-150MHz*/ + (ETH_QUARK_GMIIAR_GB); /* Start the transaction */ + + /* Wait for the transaction to complete */ + + retries = 0; + while(csrptr->gmiiar & ETH_QUARK_GMIIAR_GB) { + DELAY(ETH_QUARK_INIT_DELAY); + if((++retries) > ETH_QUARK_MAX_RETRIES) + return 0; + } + + /* Transaction is complete, read the PHY register value from */ + /* the GMII data register */ + return (uint16)csrptr->gmiidr; +} + +/*------------------------------------------------------------------------ + * eth_phy_write - Write a PHY register + *------------------------------------------------------------------------ + */ +void eth_phy_write ( + volatile struct eth_q_csreg *csrptr, /* CSR address */ + uint32 regnum, /* Register */ + uint16 value /* Value to write */ + ) +{ + uint32 retries; /* No. of retries for write */ + + /* Wait for the MII to be ready */ + + while(csrptr->gmiiar & ETH_QUARK_GMIIAR_GB); + + /* Write the value to GMII data register */ + + csrptr->gmiidr = (uint32)value; + + /* Prepare the GMII address register for write transaction */ + + csrptr->gmiiar = + (1 << 11) | /* Physical Layer Address = 1 */ + (regnum << 6) | /* PHY Register Number */ + (ETH_QUARK_GMIIAR_CR) | /* GMII Clock Range 100-150MHz*/ + (ETH_QUARK_GMIIAR_GW) | /* Write transaction */ + (ETH_QUARK_GMIIAR_GB); /* Start the transaction */ + + /* Wait till the transaction is complete */ + + retries = 0; + while(csrptr->gmiiar & ETH_QUARK_GMIIAR_GB) { + DELAY(ETH_QUARK_INIT_DELAY); + if((++retries) > ETH_QUARK_MAX_RETRIES) + return; + } +} + +/*------------------------------------------------------------------------ + * eth_phy_reset - Reset an Ethernet PHY + *------------------------------------------------------------------------ + */ +int32 eth_phy_reset ( + volatile struct eth_q_csreg *csrptr /* CSR address */ + ) +{ + uint16 value; /* Variable to read in PHY registers */ + uint32 retries; /* No. of retries for reset */ + + /* Read the PHY control register (register 0) */ + + value = eth_phy_read(csrptr, 0); + + /* Set bit 15 in control register to reset the PHY */ + + eth_phy_write(csrptr, 0, (value | 0x8000)); + + /* Wait for PHY reset process to complete */ + + retries = 0; + while(eth_phy_read(csrptr, 0) & 0x8000) { + DELAY(ETH_QUARK_INIT_DELAY); + if((++retries) > ETH_QUARK_MAX_RETRIES) + return SYSERR; + } + + /* See if the PHY has auto-negotiation capability */ + + value = eth_phy_read(csrptr, 1); /* PHY Status register */ + if(value & 0x0008) { /* Auto-negotiation capable */ + + /* Wait for the auto-negotiation process to complete */ + + retries = 0; + while((eth_phy_read(csrptr, 1) & 0x0020) == 0) { + DELAY(ETH_QUARK_INIT_DELAY); + if((++retries) > ETH_QUARK_MAX_RETRIES) + return SYSERR; + } + } + + /* Wait for the Link to be Up */ + + retries = 0; + while((eth_phy_read(csrptr, 1) & 0x0004) == 0) { + DELAY(ETH_QUARK_INIT_DELAY); + if((++retries) > ETH_QUARK_MAX_RETRIES) + return SYSERR; + } + + DELAY(100000); + + kprintf("Ethernet Link is Up\n"); + + return OK; +} + +/*------------------------------------------------------------------------ + * ethinit - Initialize the Intel Quark Ethernet device + *------------------------------------------------------------------------ + */ +int32 ethinit ( + struct dentry *devptr /* Entry in device switch table */ + ) +{ + struct ethcblk *ethptr; /* Ptr to control block */ + volatile struct eth_q_csreg *csrptr; /* Ptr to CSR */ + struct eth_q_tx_desc *tx_descs; /* Array of tx descs */ + struct eth_q_rx_desc *rx_descs; /* Array of rx descs */ + struct netpacket *pktptr; /* Pointer to a packet */ + void *temptr; /* Temp. pointer */ + uint32 retries; /* Retry count for reset*/ + int32 retval; + int32 i; + + ethptr = ðertab[devptr->dvminor]; + + ethptr->csr = (struct eth_q_csreg *)devptr->dvcsr; + csrptr = (struct eth_q_csreg *)ethptr->csr; + + /* Enable CSR Memory Space, Enable Bus Master */ + pci_write_config_word(ethptr->pcidev, 0x4, 0x0006); + + /* Reset the PHY */ + retval = eth_phy_reset(csrptr); + if(retval == SYSERR) { + return SYSERR; + } + + /* Reset the Ethernet MAC */ + csrptr->bmr |= ETH_QUARK_BMR_SWR; + + /* Wait for the MAC Reset process to complete */ + retries = 0; + while(csrptr->bmr & ETH_QUARK_BMR_SWR) { + DELAY(ETH_QUARK_INIT_DELAY); + if((++retries) > ETH_QUARK_MAX_RETRIES) + return SYSERR; + } + + /* Transmit Store and Forward */ + csrptr->omr |= ETH_QUARK_OMR_TSF; + + /* Set the interrupt handler */ + set_evec(devptr->dvirq, (uint32)devptr->dvintr); + + /* Set the MAC Speed = 100Mbps, Full Duplex mode */ + csrptr->maccr |= (ETH_QUARK_MACCR_RMIISPD100 | + ETH_QUARK_MACCR_DM); + + /* Reset the MMC Counters */ + csrptr->mmccr |= ETH_QUARK_MMC_CNTFREEZ | ETH_QUARK_MMC_CNTRST; + + /* Retrieve the MAC address from SPI flash */ + get_quark_pdat_entry_data_by_id(QUARK_MAC1_ID, + (char*)(ethptr->devAddress), ETH_ADDR_LEN); + + kprintf("MAC address is %02x:%02x:%02x:%02x:%02x:%02x\n", + 0xffðptr->devAddress[0], + 0xffðptr->devAddress[1], + 0xffðptr->devAddress[2], + 0xffðptr->devAddress[3], + 0xffðptr->devAddress[4], + 0xffðptr->devAddress[5]); + + /* Add the MAC address read from SPI flash into the */ + /* macaddr registers for address filtering */ + csrptr->macaddr0l = (uint32)(*((uint32 *)ethptr->devAddress)); + csrptr->macaddr0h = ((uint32) + (*((uint16 *)(ethptr->devAddress + 4))) | 0x80000000); + + ethptr->txRingSize = ETH_QUARK_TX_RING_SIZE; + + /* Allocate memory for the transmit ring */ + temptr = (void *)getmem(sizeof(struct eth_q_tx_desc) * + (ethptr->txRingSize+1)); + if((int)temptr == SYSERR) { + return SYSERR; + } + memset(temptr, 0, sizeof(struct eth_q_tx_desc) * + (ethptr->txRingSize+1)); + + /* The transmit descriptors need to be 4-byte aligned */ + ethptr->txRing = (void *)(((uint32)temptr + 3) & (~3)); + + /* Allocate memory for transmit buffers */ + ethptr->txBufs = (void *)getmem(sizeof(struct netpacket) * + (ethptr->txRingSize+1)); + if((int)ethptr->txBufs == SYSERR) { + return SYSERR; + } + ethptr->txBufs = (void *)(((uint32)ethptr->txBufs + 3) & (~3)); + + /* Pointers to initialize transmit descriptors */ + tx_descs = (struct eth_q_tx_desc *)ethptr->txRing; + pktptr = (struct netpacket *)ethptr->txBufs; + + /* Initialize the transmit descriptors */ + for(i = 0; i < ethptr->txRingSize; i++) { + tx_descs[i].buffer1 = (uint32)(pktptr + i); + } + + /* Create the output synchronization semaphore */ + ethptr->osem = semcreate(ethptr->txRingSize); + if((int)ethptr->osem == SYSERR) { + return SYSERR; + } + + ethptr->rxRingSize = ETH_QUARK_RX_RING_SIZE; + + /* Allocate memory for the receive descriptors */ + temptr = (void *)getmem(sizeof(struct eth_q_rx_desc) * + (ethptr->rxRingSize+1)); + if((int)temptr == SYSERR) { + return SYSERR; + } + memset(temptr, 0, sizeof(struct eth_q_rx_desc) * + (ethptr->rxRingSize+1)); + + /* Receive descriptors must be 4-byte aligned */ + ethptr->rxRing = (struct eth_q_rx_desc *) + (((uint32)temptr + 3) & (~3)); + + /* Allocate memory for the receive buffers */ + ethptr->rxBufs = (void *)getmem(sizeof(struct netpacket) * + (ethptr->rxRingSize+1)); + if((int)ethptr->rxBufs == SYSERR) { + return SYSERR; + } + + /* Receive buffers must be 4-byte aligned */ + ethptr->rxBufs = (void *)(((uint32)ethptr->rxBufs + 3) & (~3)); + + /* Pointer to initialize receive descriptors */ + rx_descs = (struct eth_q_rx_desc *)ethptr->rxRing; + + /* Pointer to data buffers */ + pktptr = (struct netpacket *)ethptr->rxBufs; + + /* Initialize the receive descriptors */ + for(i = 0; i < ethptr->rxRingSize; i++) { + + rx_descs[i].status = ETH_QUARK_RDST_OWN; + rx_descs[i].buf1size = (uint32)sizeof(struct netpacket); + rx_descs[i].buffer1 = (uint32)(pktptr + i); + } + + /* Indicate end of ring on last descriptor */ + rx_descs[ethptr->rxRingSize-1].buf1size |= (ETH_QUARK_RDCTL1_RER); + + /* Create the input synchronization semaphore */ + ethptr->isem = semcreate(0); + if((int)ethptr->isem == SYSERR) { + return SYSERR; + } + + /* Enable the Transmit and Receive Interrupts */ + csrptr->ier = ( ETH_QUARK_IER_NIE | + ETH_QUARK_IER_TIE | + ETH_QUARK_IER_RIE ); + + /* Initialize the transmit descriptor base address */ + csrptr->tdla = (uint32)ethptr->txRing; + + /* Initialize the receive descriptor base address */ + csrptr->rdla = (uint32)ethptr->rxRing; + + /* Enable the MAC Receiver and Transmitter */ + csrptr->maccr |= (ETH_QUARK_MACCR_TE | ETH_QUARK_MACCR_RE); + + /* Start the Transmit and Receive Processes in the DMA */ + csrptr->omr |= (ETH_QUARK_OMR_ST | ETH_QUARK_OMR_SR); + + return OK; + +} diff --git a/device/x86-galileo/eth/ethmcast.c b/device/x86-galileo/eth/ethmcast.c new file mode 100644 index 0000000..ca9bda6 --- /dev/null +++ b/device/x86-galileo/eth/ethmcast.c @@ -0,0 +1,79 @@ +/* ethmcast.c - ethmcast_add, ethmcast_remove */ + +#include + +/*------------------------------------------------------------------------ + * ethmcast_add - Add multicast address to Intel Quark Ethernet + *------------------------------------------------------------------------ + */ +int32 ethmcast_add ( + struct ethcblk *ethptr, /* Ptr to control block */ + byte addr[ETH_ADDR_LEN] /* Mcast addr to add */ + ) +{ + int16 mcast_count; + + struct eth_q_csreg *csrptr = (struct eth_q_csreg *)ethptr->csr; + + /*Set the Pass all multicast bit in MAC Frame Filter Register */ + + csrptr->macff |= 0x00000010; + + /* Get number of multicast addresses in array */ + + mcast_count = ethptr->ed_mcc; + + /* Add address to array, provided limit is not exceeded */ + + if(mcast_count < ETH_NUM_MCAST){ + memcpy(ethptr->ed_mca[mcast_count],addr,ETH_ADDR_LEN); + mcast_count++; + ethptr->ed_mcc = mcast_count; + return OK; + } else { + return SYSERR; + } +} + +/*------------------------------------------------------------------------ + * ethmcast_remove - Remove multicast addr. from Intel Quark Ethernet + *------------------------------------------------------------------------ + */ +int32 ethmcast_remove ( + struct ethcblk *ethptr, /* Pointer to control block */ + byte addr[ETH_ADDR_LEN] /* Mcast address to remove */ + ) +{ + int16 mcast_count; + int32 i, j; + + mcast_count = ethptr->ed_mcc; + + /* Find multicast address in the array */ + + for (i = 0; i < mcast_count; i++) { + if (memcmp(addr, ethptr->ed_mca[i], ETH_ADDR_LEN) ==0) { + + /* Shift values to fill in the hole */ + + for(j = i; j < mcast_count; j++) { + memcpy(ethptr->ed_mca[j], + ethptr->ed_mca[j+1],ETH_ADDR_LEN); + memset(ethptr->ed_mca[j+1],'0', + ETH_ADDR_LEN); + } + break; + } + } + + if(i < mcast_count) { /* Mcast address was removed */ + + /* Decrement the number of multicast addresses */ + + mcast_count--; + ethptr->ed_mcc = mcast_count; + return OK; + } else { /* Mcast address was not found */ + return SYSERR; + } +} diff --git a/device/x86-galileo/eth/ethread.c b/device/x86-galileo/eth/ethread.c new file mode 100644 index 0000000..573f040 --- /dev/null +++ b/device/x86-galileo/eth/ethread.c @@ -0,0 +1,107 @@ +/* ethread.c - ethread */ + +#include + +/*------------------------------------------------------------------------ + * ethread - Read an incoming packet on Intel Quark Ethernet + *------------------------------------------------------------------------ + */ +devcall ethread ( + struct dentry *devptr, /* Entry in device switch table */ + char *buf, /* Buffer for the packet */ + int32 len /* Size of the buffer */ + ) +{ + struct ethcblk *ethptr; /* Ethertab entry pointer */ + struct eth_q_rx_desc *rdescptr;/* Pointer to the descriptor */ + struct netpacket *pktptr; /* Pointer to packet */ + uint32 framelen = 0; /* Length of the incoming frame */ + bool8 valid_addr; + int32 i; + + ethptr = ðertab[devptr->dvminor]; + + while(1) { + + /* Wait until there is a packet in the receive queue */ + + wait(ethptr->isem); + + /* Point to the head of the descriptor list */ + + rdescptr = (struct eth_q_rx_desc *)ethptr->rxRing + + ethptr->rxHead; + pktptr = (struct netpacket*)rdescptr->buffer1; + + /* See if destination address is our unicast address */ + + if(!memcmp(pktptr->net_ethdst, ethptr->devAddress, 6)) { + valid_addr = TRUE; + + /* See if destination address is the broadcast address */ + + } else if(!memcmp(pktptr->net_ethdst, + NetData.ethbcast,6)) { + valid_addr = TRUE; + + /* For multicast addresses, see if we should accept */ + + } else { + valid_addr = FALSE; + for(i = 0; i < (ethptr->ed_mcc); i++) { + if(memcmp(pktptr->net_ethdst, + ethptr->ed_mca[i], 6) == 0){ + valid_addr = TRUE; + break; + } + } + } + + if(valid_addr == TRUE){ /* Accept this packet */ + + /* Get the length of the frame */ + + framelen = (rdescptr->status >> 16) & 0x00003FFF; + + /* Only return len characters to caller */ + + if(framelen > len) { + framelen = len; + } + + /* Copy the packet into the caller's buffer */ + + memcpy(buf, (void*)rdescptr->buffer1, framelen); + } + + /* Increment the head of the descriptor list */ + + ethptr->rxHead += 1; + if(ethptr->rxHead >= ETH_QUARK_RX_RING_SIZE) { + ethptr->rxHead = 0; + } + + /* Reset the descriptor to max possible frame len */ + + rdescptr->buf1size = sizeof(struct netpacket); + + /* If we reach the end of the ring, mark the descriptor */ + + if(ethptr->rxHead == 0) { + rdescptr->rdctl1 |= (ETH_QUARK_RDCTL1_RER); + } + + /* Indicate that the descriptor is ready for DMA input */ + + rdescptr->status = ETH_QUARK_RDST_OWN; + + if(valid_addr == TRUE) { + break; + } + } + + /* Return the number of bytes returned from the packet */ + + return framelen; + +} diff --git a/device/x86-galileo/eth/ethwrite.c b/device/x86-galileo/eth/ethwrite.c new file mode 100644 index 0000000..a5ca850 --- /dev/null +++ b/device/x86-galileo/eth/ethwrite.c @@ -0,0 +1,70 @@ +/* ethwrite.c - ethwrite */ + +#include + +/*------------------------------------------------------------------------ + * ethwrite - enqueue packet for transmission on Intel Quark Ethernet + *------------------------------------------------------------------------ + */ +devcall ethwrite ( + struct dentry *devptr, /* Entry in device switch table */ + char *buf, /* Buffer that hols a packet */ + int32 len /* Length of the packet */ + ) +{ + struct ethcblk *ethptr; /* Pointer to control block */ + struct eth_q_csreg *csrptr; /* Address of device CSRs */ + volatile struct eth_q_tx_desc *descptr; /* Ptr to descriptor */ + uint32 i; /* Counts bytes during copy */ + + ethptr = ðertab[devptr->dvminor]; + + csrptr = (struct eth_q_csreg *)ethptr->csr; + + /* Wait for an empty slot in the transmit descriptor ring */ + + wait(ethptr->osem); + + /* Point to the tail of the descriptor ring */ + + descptr = (struct eth_q_tx_desc *)ethptr->txRing + ethptr->txTail; + + /* Increment the tail index and wrap, if needed */ + + ethptr->txTail += 1; + if(ethptr->txTail >= ethptr->txRingSize) { + ethptr->txTail = 0; + } + + /* Add packet length to the descriptor */ + + descptr->buf1size = len; + + /* Copy packet into the buffer associated with the descriptor */ + + for(i = 0; i < len; i++) { + *((char *)descptr->buffer1 + i) = *((char *)buf + i); + } + + /* Mark the descriptor if we are at the end of the ring */ + + if(ethptr->txTail == 0) { + descptr->ctrlstat = ETH_QUARK_TDCS_TER; + } else { + descptr->ctrlstat = 0; + } + + /* Initialize the descriptor */ + + descptr->ctrlstat |= + (ETH_QUARK_TDCS_OWN | /* The desc is owned by DMA */ + ETH_QUARK_TDCS_IC | /* Interrupt after transfer */ + ETH_QUARK_TDCS_LS | /* Last segment of packet */ + ETH_QUARK_TDCS_FS); /* First segment of packet */ + + /* Un-suspend DMA on the device */ + + csrptr->tpdr = 1; + + return OK; +} diff --git a/device/x86-galileo/lfs/lfdballoc.c b/device/x86-galileo/lfs/lfdballoc.c new file mode 100644 index 0000000..bafb418 --- /dev/null +++ b/device/x86-galileo/lfs/lfdballoc.c @@ -0,0 +1,40 @@ +/* lfdballoc.c - lfdballoc */ + +#include + +#define DFILL '+' /* character used to fill a disk block */ + +/*------------------------------------------------------------------------ + * lfdballoc - Allocate a new data block from free list on disk + * (assumes directory mutex held) + *------------------------------------------------------------------------ + */ +dbid32 lfdballoc ( + struct lfdbfree *dbuff /* Addr. of buffer to hold data block */ + ) +{ + dbid32 dnum; /* ID of next d-block on the free list */ + int32 retval; /* Return value */ + + /* Get the ID of first data block on the free list */ + + dnum = Lf_data.lf_dir.lfd_dfree; + if (dnum == LF_DNULL) { /* Ran out of free data blocks */ + panic("out of data blocks"); + } + retval = read(Lf_data.lf_dskdev, (char *)dbuff, dnum); + if (retval == SYSERR) { + panic("lfdballoc cannot read disk block\n\r"); + } + + /* Unlink d-block from in-memory directory */ + + Lf_data.lf_dir.lfd_dfree = dbuff->lf_nextdb; + write(Lf_data.lf_dskdev, (char *)&Lf_data.lf_dir, LF_AREA_DIR); + Lf_data.lf_dirdirty = FALSE; + + /* Fill data block to erase old data */ + + memset((char *)dbuff, DFILL, LF_BLKSIZ); + return dnum; +} diff --git a/device/x86-galileo/lfs/lfdbfree.c b/device/x86-galileo/lfs/lfdbfree.c new file mode 100644 index 0000000..d23eadc --- /dev/null +++ b/device/x86-galileo/lfs/lfdbfree.c @@ -0,0 +1,25 @@ +/* lfdbfree.c - lfdbfree */ + +#include + +/*------------------------------------------------------------------------ + * lfdbfree - Free a data block given its block number (assumes + * directory mutex is held) + *------------------------------------------------------------------------ + */ +status lfdbfree( + did32 diskdev, /* ID of disk device to use */ + dbid32 dnum /* ID of data block to free */ + ) +{ + struct lfdir *dirptr; /* Pointer to directory */ + struct lfdbfree buf; /* Buffer to hold data block */ + + dirptr = &Lf_data.lf_dir; + buf.lf_nextdb = dirptr->lfd_dfree; + dirptr->lfd_dfree = dnum; + write(diskdev, (char *)&buf, dnum); + write(diskdev, (char *)dirptr, LF_AREA_DIR); + + return OK; +} diff --git a/device/x86-galileo/lfs/lfflush.c b/device/x86-galileo/lfs/lfflush.c new file mode 100644 index 0000000..89d1ff6 --- /dev/null +++ b/device/x86-galileo/lfs/lfflush.c @@ -0,0 +1,42 @@ +/* lfflush.c - lfflush */ + +#include + +/*------------------------------------------------------------------------ + * lfflush - Flush directory, data block, and index block for an open + * file (assumes file mutex is held) + *------------------------------------------------------------------------ + */ +status lfflush ( + struct lflcblk *lfptr /* Ptr to file pseudo device */ + ) +{ + + if (lfptr->lfstate == LF_FREE) { + return SYSERR; + } + + /* Write the directory if it has changed */ + + if (Lf_data.lf_dirdirty) { + write(Lf_data.lf_dskdev, (char *)&Lf_data.lf_dir, + LF_AREA_DIR); + Lf_data.lf_dirdirty = FALSE; + } + + /* Write data block if it has changed */ + + if (lfptr->lfdbdirty) { + write(Lf_data.lf_dskdev, lfptr->lfdblock, lfptr->lfdnum); + lfptr->lfdbdirty = FALSE; + } + + /* Write i-block if it has changed */ + + if (lfptr->lfibdirty) { + lfibput(Lf_data.lf_dskdev, lfptr->lfinum, &lfptr->lfiblock); + lfptr->lfibdirty = FALSE; + } + + return OK; +} diff --git a/device/x86-galileo/lfs/lfgetmode.c b/device/x86-galileo/lfs/lfgetmode.c new file mode 100644 index 0000000..cf81090 --- /dev/null +++ b/device/x86-galileo/lfs/lfgetmode.c @@ -0,0 +1,61 @@ +/* lfgetmode.c - lfgetmode */ + +#include + +/*------------------------------------------------------------------------ + * lfgetmode - Parse mode argument and generate integer of mode bits + *------------------------------------------------------------------------ + */ +int32 lfgetmode ( + char *mode /* String of mode characters */ + ) +{ + int32 mbits; /* Mode bits to return */ + char ch; /* Next char in mode string */ + + mbits = 0; + + /* Mode string specifies: */ + /* r - read */ + /* w - write */ + /* o - old (file must exist) */ + /* n - new (create a new file) */ + + while ( (ch = *mode++) != NULLCH) { + switch (ch) { + + case 'r': if (mbits&LF_MODE_R) { + return SYSERR; + } + mbits |= LF_MODE_R; + continue; + + case 'w': if (mbits&LF_MODE_W) { + return SYSERR; + } + mbits |= LF_MODE_W; + continue; + + case 'o': if (mbits&LF_MODE_O || mbits&LF_MODE_N) { + return SYSERR; + } + mbits |= LF_MODE_O; + break; + + case 'n': if (mbits&LF_MODE_O || mbits&LF_MODE_N) { + return SYSERR; + } + mbits |= LF_MODE_N; + break; + + default: return SYSERR; + } + } + + /* If neither read nor write specified, allow both */ + + if ( (mbits&LF_MODE_RW) == 0 ) { + mbits |= LF_MODE_RW; + } + return mbits; +} diff --git a/device/x86-galileo/lfs/lfiballoc.c b/device/x86-galileo/lfs/lfiballoc.c new file mode 100644 index 0000000..16eb4c3 --- /dev/null +++ b/device/x86-galileo/lfs/lfiballoc.c @@ -0,0 +1,33 @@ +/* lfiballoc.c - lfiballoc */ + +#include + +/*------------------------------------------------------------------------ + * lfiballoc - Allocate a new index block from free list on disk + * (assumes directory mutex held) + *------------------------------------------------------------------------ + */ +ibid32 lfiballoc (void) +{ + ibid32 ibnum; /* ID of next block on the free list */ + struct lfiblk iblock; /* Buffer to hold an index block */ + + /* Get ID of first index block on free list */ + + ibnum = Lf_data.lf_dir.lfd_ifree; + if (ibnum == LF_INULL) { /* Ran out of free index blocks */ + panic("out of index blocks"); + } + lfibget(Lf_data.lf_dskdev, ibnum, &iblock); + + /* Unlink index block from the directory free list */ + + Lf_data.lf_dir.lfd_ifree = iblock.ib_next; + + /* Write a copy of the directory to disk after the change */ + + write(Lf_data.lf_dskdev, (char *) &Lf_data.lf_dir, LF_AREA_DIR); + Lf_data.lf_dirdirty = FALSE; + + return ibnum; +} diff --git a/device/x86-galileo/lfs/lfibclear.c b/device/x86-galileo/lfs/lfibclear.c new file mode 100644 index 0000000..9d0cf3d --- /dev/null +++ b/device/x86-galileo/lfs/lfibclear.c @@ -0,0 +1,22 @@ +/* lfibclear.c - lfibclear */ + +#include + +/*------------------------------------------------------------------------ + * lfibclear -- Clear an in-core copy of an index block + *------------------------------------------------------------------------ + */ +void lfibclear( + struct lfiblk *ibptr, /* Address of i-block in memory */ + int32 offset /* File offset for this i-block */ + ) +{ + int32 i; /* Index for data block array */ + + ibptr->ib_offset = offset; /* Assign specified file offset */ + for (i=0 ; iib_dba[i] = LF_DNULL; + } + ibptr->ib_next = LF_INULL; /* Set next ptr to null */ + return; +} diff --git a/device/x86-galileo/lfs/lfibget.c b/device/x86-galileo/lfs/lfibget.c new file mode 100644 index 0000000..4e69f1d --- /dev/null +++ b/device/x86-galileo/lfs/lfibget.c @@ -0,0 +1,31 @@ +/* lfibget.c - lfibget */ + +#include + +/*------------------------------------------------------------------------ + * lfibget - Get an index block from disk given its number (assumes + * mutex is held) + *------------------------------------------------------------------------ + */ +void lfibget( + did32 diskdev, /* Device ID of disk to use */ + ibid32 inum, /* ID of index block to fetch */ + struct lfiblk *ibuff /* Buffer to hold index block */ + ) +{ + char *from, *to; /* Pointers used in copying */ + int32 i; /* Loop index used during copy */ + char dbuff[LF_BLKSIZ]; /* Buffer to hold disk block */ + + /* Read disk block that contains the specified index block */ + + read(diskdev, dbuff, ib2sect(inum)); + + /* Copy specified index block to caller's ibuff */ + + from = dbuff + ib2disp(inum); + to = (char *)ibuff; + for (i=0 ; i + +/*------------------------------------------------------------------------ + * lfibput - Write an index block to disk given its ID (assumes + * mutex is held) + *------------------------------------------------------------------------ + */ +status lfibput( + did32 diskdev, /* ID of disk device */ + ibid32 inum, /* ID of index block to write */ + struct lfiblk *ibuff /* Buffer holding the index blk */ + ) +{ + dbid32 diskblock; /* ID of disk sector (block) */ + char *from, *to; /* Pointers used in copying */ + int32 i; /* Loop index used during copy */ + char dbuff[LF_BLKSIZ]; /* Temp. buffer to hold d-block */ + + /* Compute disk block number and offset of index block */ + + diskblock = ib2sect(inum); + to = dbuff + ib2disp(inum); + from = (char *)ibuff; + + /* Read disk block */ + + if (read(diskdev, dbuff, diskblock) == SYSERR) { + return SYSERR; + } + + /* Copy index block into place */ + + for (i=0 ; i + +/*------------------------------------------------------------------------ + * lflclose - Close a file by flushing output and freeing device entry + *------------------------------------------------------------------------ + */ +devcall lflclose ( + struct dentry *devptr /* Entry in device switch table */ + ) +{ + struct lflcblk *lfptr; /* Ptr to open file table entry */ + + /* Obtain exclusive use of the file */ + + lfptr = &lfltab[devptr->dvminor]; + wait(lfptr->lfmutex); + + /* If file is not open, return an error */ + + if (lfptr->lfstate != LF_USED) { + signal(lfptr->lfmutex); + return SYSERR; + } + + /* Write index or data blocks to disk if they have changed */ + + if (Lf_data.lf_dirdirty || lfptr->lfdbdirty || lfptr->lfibdirty) { + lfflush(lfptr); + } + + /* Set device state to FREE and return to caller */ + + lfptr->lfstate = LF_FREE; + signal(lfptr->lfmutex); + return OK; +} diff --git a/device/x86-galileo/lfs/lflcontrol.c b/device/x86-galileo/lfs/lflcontrol.c new file mode 100644 index 0000000..a023098 --- /dev/null +++ b/device/x86-galileo/lfs/lflcontrol.c @@ -0,0 +1,47 @@ +/* lflcontrol.c - lflcontrol */ + +#include + +/*------------------------------------------------------------------------ + * lflcontrol - Provide control functions for a local file pseudo-device + *------------------------------------------------------------------------ + */ +devcall lflcontrol ( + struct dentry *devptr, /* Entry in device switch table */ + int32 func, /* A control function */ + int32 arg1, /* Argument #1 */ + int32 arg2 /* Argument #2 */ + ) +{ + struct lflcblk *lfptr; /* Ptr to open file table entry */ + int32 retval; /* Return value from func. call */ + + /* Obtain exclusive use of the file */ + + lfptr = &lfltab[devptr->dvminor]; + wait(lfptr->lfmutex); + + /* If file is not open, return an error */ + + if (lfptr->lfstate != LF_USED) { + signal(lfptr->lfmutex); + return SYSERR; + } + + switch (func) { + + /* Truncate a file */ + + case LF_CTL_TRUNC: + wait(Lf_data.lf_mutex); + retval = lftruncate(lfptr); + signal(Lf_data.lf_mutex); + signal(lfptr->lfmutex); + return retval; + + default: + kprintf("lfcontrol: function %d not valid\n\r", func); + signal(lfptr->lfmutex); + return SYSERR; + } +} diff --git a/device/x86-galileo/lfs/lflgetc.c b/device/x86-galileo/lfs/lflgetc.c new file mode 100644 index 0000000..822d0c8 --- /dev/null +++ b/device/x86-galileo/lfs/lflgetc.c @@ -0,0 +1,52 @@ +/* lflgetc.c - lfgetc */ + +#include + +/*------------------------------------------------------------------------ + * lflgetc - Read the next byte from an open local file + *------------------------------------------------------------------------ + */ +devcall lflgetc ( + struct dentry *devptr /* Entry in device switch table */ + ) +{ + struct lflcblk *lfptr; /* Ptr to open file table entry */ + struct ldentry *ldptr; /* Ptr to file's entry in the */ + /* in-memory directory */ + int32 onebyte; /* Next data byte in the file */ + + /* Obtain exclusive use of the file */ + + lfptr = &lfltab[devptr->dvminor]; + wait(lfptr->lfmutex); + + /* If file is not open, return an error */ + + if (lfptr->lfstate != LF_USED) { + signal(lfptr->lfmutex); + return SYSERR; + } + + /* Return EOF for any attempt to read beyond the end-of-file */ + + ldptr = lfptr->lfdirptr; + if (lfptr->lfpos >= ldptr->ld_size) { + signal(lfptr->lfmutex); + return EOF; + } + + /* If byte pointer is beyond the current data block, set up */ + /* a new data block */ + + if (lfptr->lfbyte >= &lfptr->lfdblock[LF_BLKSIZ]) { + lfsetup(lfptr); + } + + /* Extract the next byte from block, update file position, and */ + /* return the byte to the caller */ + + onebyte = 0xff & *lfptr->lfbyte++; + lfptr->lfpos++; + signal(lfptr->lfmutex); + return onebyte; +} diff --git a/device/x86-galileo/lfs/lflinit.c b/device/x86-galileo/lfs/lflinit.c new file mode 100644 index 0000000..c3f4e13 --- /dev/null +++ b/device/x86-galileo/lfs/lflinit.c @@ -0,0 +1,46 @@ +/* lflinit.c - lflinit */ + +#include + +struct lflcblk lfltab[Nlfl]; /* Pseudo-device control blocks */ + +/*------------------------------------------------------------------------ + * lflinit - Initialize control blocks for local file pseudo-devices + *------------------------------------------------------------------------ + */ +devcall lflinit ( + struct dentry *devptr /* Entry in device switch table */ + ) +{ + struct lflcblk *lfptr; /* Ptr. to control block entry */ + int32 i; /* Walks through name array */ + + lfptr = &lfltab[ devptr->dvminor ]; + + /* Initialize control block entry */ + + lfptr->lfstate = LF_FREE; /* Device is currently unused */ + lfptr->lfdev = devptr->dvnum; /* Set device ID */ + lfptr->lfmutex = semcreate(1); /* Create the mutex semaphore */ + + /* Initialize the directory and file position */ + + lfptr->lfdirptr = (struct ldentry *) NULL; + lfptr->lfpos = 0; + for (i=0; ilfname[i] = NULLCH; + } + + /* Zero the in-memory index block and data block */ + + lfptr->lfinum = LF_INULL; + memset((char *) &lfptr->lfiblock, NULLCH, sizeof(struct lfiblk)); + lfptr->lfdnum = 0; + memset((char *) &lfptr->lfdblock, NULLCH, LF_BLKSIZ); + + /* Start with the byte beyond the current data block */ + + lfptr->lfbyte = &lfptr->lfdblock[LF_BLKSIZ]; + lfptr->lfibdirty = lfptr->lfdbdirty = FALSE; + return OK; +} diff --git a/device/x86-galileo/lfs/lflputc.c b/device/x86-galileo/lfs/lflputc.c new file mode 100644 index 0000000..8184c5d --- /dev/null +++ b/device/x86-galileo/lfs/lflputc.c @@ -0,0 +1,64 @@ +/* lflputc.c - lfputc */ + +#include + +/*------------------------------------------------------------------------ + * lflputc - Write a single byte to an open local file + *------------------------------------------------------------------------ + */ +devcall lflputc ( + struct dentry *devptr, /* Entry in device switch table */ + char ch /* Character (byte) to write */ + ) +{ + struct lflcblk *lfptr; /* Ptr to open file table entry */ + struct ldentry *ldptr; /* Ptr to file's entry in the */ + /* in-memory directory */ + + /* Obtain exclusive use of the file */ + + lfptr = &lfltab[devptr->dvminor]; + wait(lfptr->lfmutex); + + /* If file is not open, return an error */ + + if (lfptr->lfstate != LF_USED) { + signal(lfptr->lfmutex); + return SYSERR; + } + + /* Return SYSERR for an attempt to skip bytes beyond the byte */ + /* that is currently the end of the file */ + + ldptr = lfptr->lfdirptr; + if (lfptr->lfpos > ldptr->ld_size) { + signal(lfptr->lfmutex); + return SYSERR; + } + + /* If pointer is outside current block, set up new block */ + + if (lfptr->lfbyte >= &lfptr->lfdblock[LF_BLKSIZ]) { + + /* Set up block for current file position */ + + lfsetup(lfptr); + } + + /* If appending a byte to the file, increment the file size. */ + /* Note: comparison might be equal, but should not be greater.*/ + + if (lfptr->lfpos >= ldptr->ld_size) { + ldptr->ld_size++; + Lf_data.lf_dirdirty = TRUE; + } + + /* Place byte in buffer and mark buffer "dirty" */ + + *lfptr->lfbyte++ = ch; + lfptr->lfpos++; + lfptr->lfdbdirty = TRUE; + + signal(lfptr->lfmutex); + return OK; +} diff --git a/device/x86-galileo/lfs/lflread.c b/device/x86-galileo/lfs/lflread.c new file mode 100644 index 0000000..acc9caa --- /dev/null +++ b/device/x86-galileo/lfs/lflread.c @@ -0,0 +1,39 @@ +/* lflread.c - lflread */ + +#include + +/*------------------------------------------------------------------------ + * lflread - Read from a previously opened local file + *------------------------------------------------------------------------ + */ +devcall lflread ( + struct dentry *devptr, /* Entry in device switch table */ + char *buff, /* Buffer to hold bytes */ + int32 count /* Max bytes to read */ + ) +{ + uint32 numread; /* Number of bytes read */ + int32 nxtbyte; /* Character or SYSERR/EOF */ + + if (count < 0) { + return SYSERR; + } + + /* Iterate and use lflgetc to read indivdiual bytes */ + + for (numread=0 ; numread < count ; numread++) { + nxtbyte = lflgetc(devptr); + if (nxtbyte == SYSERR) { + return SYSERR; + } else if (nxtbyte == EOF) { /* EOF before finished */ + if (numread == 0) { + return EOF; + } else { + return numread; + } + } else { + *buff++ = (char) (0xff & nxtbyte); + } + } + return numread; +} diff --git a/device/x86-galileo/lfs/lflseek.c b/device/x86-galileo/lfs/lflseek.c new file mode 100644 index 0000000..e0076c2 --- /dev/null +++ b/device/x86-galileo/lfs/lflseek.c @@ -0,0 +1,41 @@ +/* lflseek.c - lflseek */ + +#include + +/*------------------------------------------------------------------------ + * lflseek - Seek to a specified position in a file + *------------------------------------------------------------------------ + */ +devcall lflseek ( + struct dentry *devptr, /* Entry in device switch table */ + uint32 offset /* Byte position in the file */ + ) +{ + struct lflcblk *lfptr; /* Ptr to open file table entry */ + + /* If file is not open, return an error */ + + lfptr = &lfltab[devptr->dvminor]; + wait(lfptr->lfmutex); + if (lfptr->lfstate != LF_USED) { + signal(lfptr->lfmutex); + return SYSERR; + } + + /* Verify offset is within current file size */ + + if (offset > lfptr->lfdirptr->ld_size) { + signal(lfptr->lfmutex); + return SYSERR; + } + + /* Record new offset and invalidate byte pointer (i.e., force */ + /* the index and data blocks to be replaced if a successive */ + /* call is made to read or write) */ + + lfptr->lfpos = offset; + lfptr->lfbyte = &lfptr->lfdblock[LF_BLKSIZ]; + + signal(lfptr->lfmutex); + return OK; +} diff --git a/device/x86-galileo/lfs/lflwrite.c b/device/x86-galileo/lfs/lflwrite.c new file mode 100644 index 0000000..ce924c4 --- /dev/null +++ b/device/x86-galileo/lfs/lflwrite.c @@ -0,0 +1,29 @@ +/* lflwrite.c - lflwrite */ + +#include + +/*------------------------------------------------------------------------ + * lflwrite -- Write data to a previously opened local disk file + *------------------------------------------------------------------------ + */ +devcall lflwrite ( + struct dentry *devptr, /* Entry in device switch table */ + char *buff, /* Buffer holding data to write */ + int32 count /* Number of bytes to write */ + ) +{ + int32 i; /* Number of bytes written */ + + if (count < 0) { + return SYSERR; + } + + /* Iteratate and write one byte at a time */ + + for (i=0; i +#include + +/*------------------------------------------------------------------------ + * lfckfmt - Check the format of an initially-created disk + *------------------------------------------------------------------------ + */ +status lfsckfmt ( + did32 disk /* ID of an open disk device */ + ) +{ + uint32 ibsectors; /* Number of sectors of i-blocks*/ + struct lfdir dir; /* Buffer to hold the directory */ + uint32 dblks; /* Total free data blocks */ + struct lfiblk iblock; /* Space for one i-block */ + struct lfdbfree dblock; /* Data block on the free list */ + int32 lfiblks; /* Total free index blocks */ + int32 retval; + ibid32 nextib; + dbid32 nextdb; + + /* Read directory */ + + retval = read(disk,(char *)&dir, LF_AREA_DIR); + if (retval == SYSERR) { + panic("cannot read directory"); + } + kprintf("Have read directory from disk device %d\n\r", + disk); + + /* Follow index block list */ + + lfiblks = 0; + nextib = dir.lfd_ifree; + kprintf("initial index block is %d\n\r", nextib); + while (nextib != LF_INULL) { + lfiblks++; + lfibget(disk, nextib, &iblock); + nextib = iblock.ib_next; + } + ibsectors = (lfiblks + 6) /7; + kprintf("Found %d index blocks (%d sectors)\n\r", lfiblks, ibsectors); + + /* Follow data block list */ + + dblks = 0; + nextdb = dir.lfd_dfree; + kprintf("initial data block is %d\n\r", nextdb); + while (nextdb != LF_DNULL) { + dblks++; + read(disk, (char *)&dblock, nextdb); + nextdb = dblock.lf_nextdb; + } + kprintf("Found %d data blocks\n\r", dblks); + return OK; +} diff --git a/device/x86-galileo/lfs/lfscreate.c b/device/x86-galileo/lfs/lfscreate.c new file mode 100644 index 0000000..68ba943 --- /dev/null +++ b/device/x86-galileo/lfs/lfscreate.c @@ -0,0 +1,74 @@ +/* lfscreate.c - lfscreate */ + +#include +#include + +/*------------------------------------------------------------------------ + * lfscreate - Create an initially-empty file system on a disk + *------------------------------------------------------------------------ + */ +status lfscreate ( + did32 disk, /* ID of an open disk device */ + ibid32 lfiblks, /* Num. of index blocks on disk */ + uint32 dsiz /* Total size of disk in bytes */ + ) +{ + uint32 sectors; /* Number of sectors to use */ + uint32 ibsectors; /* Number of sectors of i-blocks*/ + uint32 ibpersector; /* Number of i-blocks per sector*/ + struct lfdir dir; /* Buffer to hold the directory */ + uint32 dblks; /* Total free data blocks */ + struct lfiblk iblock; /* Space for one i-block */ + struct lfdbfree dblock; /* Data block on the free list */ + dbid32 dbindex; /* Index for data blocks */ + int32 retval; /* Return value from func call */ + int32 i; /* Loop index */ + + /* Compute total sectors on disk */ + + sectors = dsiz / LF_BLKSIZ; /* Truncate to full sector */ + + /* Compute number of sectors comprising i-blocks */ + + ibpersector = LF_BLKSIZ / sizeof(struct lfiblk); + ibsectors = (lfiblks+(ibpersector-1)) / ibpersector;/* Round up */ + lfiblks = ibsectors * ibpersector; + if (ibsectors > sectors/2) { /* Invalid arguments */ + return SYSERR; + } + + /* Create an initial directory */ + + memset((char *)&dir, NULLCH, sizeof(struct lfdir)); + dir.lfd_nfiles = 0; + dbindex= (dbid32)(ibsectors + 1); + dir.lfd_dfree = dbindex; + dblks = sectors - ibsectors - 1; + retval = write(disk,(char *)&dir, LF_AREA_DIR); + if (retval == SYSERR) { + return SYSERR; + } + + /* Create list of free i-blocks on disk */ + + lfibclear(&iblock, 0); + for (i=0; i + +/*------------------------------------------------------------------------ + * lfsetup - Set a file's index block and data block for the current + * file position (assumes file mutex held) + *------------------------------------------------------------------------ + */ +status lfsetup ( + struct lflcblk *lfptr /* Pointer to slave file device */ + ) +{ + dbid32 dnum; /* Data block to fetch */ + ibid32 ibnum; /* I-block number during search */ + struct ldentry *ldptr; /* Ptr to file entry in dir. */ + struct lfiblk *ibptr; /* Ptr to in-memory index block */ + uint32 newoffset; /* Computed data offset for */ + /* next index block */ + int32 dindex; /* Index into array in an index */ + /* block */ + + + /* Obtain exclusive access to the directory */ + + wait(Lf_data.lf_mutex); + + /* Get pointers to in-memory directory, file's entry in the */ + /* directory, and the in-memory index block */ + + ldptr = lfptr->lfdirptr; + ibptr = &lfptr->lfiblock; + + /* If existing index block or data block changed, write to disk */ + + if (lfptr->lfibdirty || lfptr->lfdbdirty) { + lfflush(lfptr); + } + ibnum = lfptr->lfinum; /* Get ID of curr. index block */ + + /* If there is no index block in memory (e.g., because the file */ + /* was just opened), either load the first index block of */ + /* the file or allocate a new first index block */ + + if (ibnum == LF_INULL) { + + /* Check directory entry to see if index block exists */ + + ibnum = ldptr->ld_ilist; + if (ibnum == LF_INULL) { /* Empty file - get new i-block*/ + ibnum = lfiballoc(); + lfibclear(ibptr, 0); + ldptr->ld_ilist = ibnum; + lfptr->lfibdirty = TRUE; + } else { /* Nonempty - read first i-block*/ + lfibget(Lf_data.lf_dskdev, ibnum, ibptr); + } + lfptr->lfinum = ibnum; + + /* Otherwise, if current file position has been moved to an */ + /* offset before the current index block, start at the */ + /* beginning of the index list for the file */ + + } else if (lfptr->lfpos < ibptr->ib_offset) { + + /* Load initial index block for the file (we know that */ + /* at least one index block exists) */ + + ibnum = ldptr->ld_ilist; + lfibget(Lf_data.lf_dskdev, ibnum, ibptr); + lfptr->lfinum = ibnum; + } + + /* At this point, an index block is in memory, but may cover */ + /* an offset less than the current file position. Loop until */ + /* the index block covers the current file position. */ + + while ((lfptr->lfpos & ~LF_IMASK) > ibptr->ib_offset ) { + ibnum = ibptr->ib_next; + if (ibnum == LF_INULL) { + /* Allocate new index block to extend file */ + ibnum = lfiballoc(); + ibptr->ib_next = ibnum; + lfibput(Lf_data.lf_dskdev, lfptr->lfinum, ibptr); + lfptr->lfinum = ibnum; + newoffset = ibptr->ib_offset + LF_IDATA; + lfibclear(ibptr, newoffset); + lfptr->lfibdirty = TRUE; + } else { + lfibget(Lf_data.lf_dskdev, ibnum, ibptr); + lfptr->lfinum = ibnum; + } + lfptr->lfdnum = LF_DNULL; /* Invalidate old data block */ + } + + /* At this point, the index block in lfiblock covers the */ + /* current file position (i.e., position lfptr->lfpos). The */ + /* next step consists of loading the correct data block. */ + + dindex = (lfptr->lfpos & LF_IMASK) >> 9; + + /* If data block index does not match current data block, read */ + /* the correct data block from disk */ + + dnum = lfptr->lfiblock.ib_dba[dindex]; + if (dnum == LF_DNULL) { /* Allocate new data block */ + dnum = lfdballoc((struct lfdbfree *)&lfptr->lfdblock); + lfptr->lfiblock.ib_dba[dindex] = dnum; + lfptr->lfibdirty = TRUE; + } else if ( dnum != lfptr->lfdnum) { + read(Lf_data.lf_dskdev, (char *)lfptr->lfdblock, dnum); + lfptr->lfdbdirty = FALSE; + } + lfptr->lfdnum = dnum; + + /* Use current file offset to set the pointer to the next byte */ + /* within the data block */ + + lfptr->lfbyte = &lfptr->lfdblock[lfptr->lfpos & LF_DMASK]; + signal(Lf_data.lf_mutex); + return OK; +} diff --git a/device/x86-galileo/lfs/lfsinit.c b/device/x86-galileo/lfs/lfsinit.c new file mode 100644 index 0000000..d9ab814 --- /dev/null +++ b/device/x86-galileo/lfs/lfsinit.c @@ -0,0 +1,32 @@ +/* lfsinit.c - lfsinit */ + +#include + +struct lfdata Lf_data; + +/*------------------------------------------------------------------------ + * lfsinit - Initialize the local file system master device + *------------------------------------------------------------------------ + */ +devcall lfsinit ( + struct dentry *devptr /* Entry in device switch table */ + ) +{ + /* Assign ID of disk device that will be used */ + + Lf_data.lf_dskdev = LF_DISK_DEV; + + /* Create a mutual exclusion semaphore */ + + Lf_data.lf_mutex = semcreate(1); + + /* Zero directory area (for debugging) */ + + memset((char *)&Lf_data.lf_dir, NULLCH, sizeof(struct lfdir)); + + /* Initialize directory to "not present" in memory */ + + Lf_data.lf_dirpresent = Lf_data.lf_dirdirty = FALSE; + + return OK; +} diff --git a/device/x86-galileo/lfs/lfsopen.c b/device/x86-galileo/lfs/lfsopen.c new file mode 100644 index 0000000..4613ee9 --- /dev/null +++ b/device/x86-galileo/lfs/lfsopen.c @@ -0,0 +1,180 @@ +/* lfsopen.c - lfsopen */ + +#include + +/*------------------------------------------------------------------------ + * lfsopen - Open a file and allocate a local file pseudo-device + *------------------------------------------------------------------------ + */ +devcall lfsopen ( + struct dentry *devptr, /* Entry in device switch table */ + char *name, /* Name of file to open */ + char *mode /* Mode chars: 'r' 'w' 'o' 'n' */ + ) +{ + struct lfdir *dirptr; /* Ptr to in-memory directory */ + char *from, *to; /* Ptrs used during copy */ + char *nam, *cmp; /* Ptrs used during comparison */ + int32 i; /* General loop index */ + did32 lfnext; /* Minor number of an unused */ + /* file pseudo-device */ + struct ldentry *ldptr; /* Ptr to an entry in directory */ + struct lflcblk *lfptr; /* Ptr to open file table entry */ + bool8 found; /* Was the name found? */ + int32 retval; /* Value returned from function */ + int32 mbits; /* Mode bits */ + + /* Check length of name file (leaving space for NULLCH */ + + from = name; + for (i=0; i< LF_NAME_LEN; i++) { + if (*from++ == NULLCH) { + break; + } + } + if (i >= LF_NAME_LEN) { /* Name is too long */ + return SYSERR; + } + + /* Parse mode argument and convert to binary */ + + mbits = lfgetmode(mode); + if (mbits == SYSERR) { + return SYSERR; + } + + /* If named file is already open, return SYSERR */ + + lfnext = SYSERR; + for (i=0; ilfstate == LF_FREE) { + if (lfnext == SYSERR) { + lfnext = i; /* Record index */ + } + continue; + } + + /* Compare requested name to name of open file */ + + nam = name; + cmp = lfptr->lfname; + while(*nam != NULLCH) { + if (*nam != *cmp) { + break; + } + nam++; + cmp++; + } + + /* See if comparison succeeded */ + + if ( (*nam==NULLCH) && (*cmp == NULLCH) ) { + return SYSERR; + } + } + if (lfnext == SYSERR) { /* No slave file devices are available */ + return SYSERR; + } + + /* Obtain copy of directory if not already present in memory */ + + dirptr = &Lf_data.lf_dir; + wait(Lf_data.lf_mutex); + if (! Lf_data.lf_dirpresent) { + retval = read(Lf_data.lf_dskdev,(char *)dirptr,LF_AREA_DIR); + if (retval == SYSERR ) { + signal(Lf_data.lf_mutex); + return SYSERR; + } + Lf_data.lf_dirpresent = TRUE; + } + + /* Search directory to see if file exists */ + + found = FALSE; + for (i=0; ilfd_nfiles; i++) { + ldptr = &dirptr->lfd_files[i]; + nam = name; + cmp = ldptr->ld_name; + while(*nam != NULLCH) { + if (*nam != *cmp) { + break; + } + nam++; + cmp++; + } + if ( (*nam==NULLCH) && (*cmp==NULLCH) ) { /* Name found */ + found = TRUE; + break; + } + } + + /* Case #1 - file is not in directory (i.e., does not exist) */ + + if (! found) { + if (mbits & LF_MODE_O) { /* File *must* exist */ + signal(Lf_data.lf_mutex); + return SYSERR; + } + + /* Take steps to create new file and add to directory */ + + /* Verify that space remains in the directory */ + + if (dirptr->lfd_nfiles >= LF_NUM_DIR_ENT) { + signal(Lf_data.lf_mutex); + return SYSERR; + } + + /* Allocate next dir. entry & initialize to empty file */ + + ldptr = &dirptr->lfd_files[dirptr->lfd_nfiles++]; + ldptr->ld_size = 0; + from = name; + to = ldptr->ld_name; + while ( (*to++ = *from++) != NULLCH ) { + ; + } + ldptr->ld_ilist = LF_INULL; + + /* Case #2 - file is in directory (i.e., already exists) */ + + } else if (mbits & LF_MODE_N) { /* File must not exist */ + signal(Lf_data.lf_mutex); + return SYSERR; + } + + /* Initialize the local file pseudo-device */ + + lfptr = &lfltab[lfnext]; + lfptr->lfstate = LF_USED; + lfptr->lfdirptr = ldptr; /* Point to directory entry */ + lfptr->lfmode = mbits & LF_MODE_RW; + + /* File starts at position 0 */ + + lfptr->lfpos = 0; + + to = lfptr->lfname; + from = name; + while ( (*to++ = *from++) != NULLCH ) { + ; + } + + /* Neither index block nor data block are initially valid */ + + lfptr->lfinum = LF_INULL; + lfptr->lfdnum = LF_DNULL; + + /* Initialize byte pointer to address beyond the end of the */ + /* buffer (i.e., invalid pointer triggers setup) */ + + lfptr->lfbyte = &lfptr->lfdblock[LF_BLKSIZ]; + lfptr->lfibdirty = FALSE; + lfptr->lfdbdirty = FALSE; + + signal(Lf_data.lf_mutex); + + return lfptr->lfdev; +} diff --git a/device/x86-galileo/lfs/lftruncate.c b/device/x86-galileo/lfs/lftruncate.c new file mode 100644 index 0000000..519ad71 --- /dev/null +++ b/device/x86-galileo/lfs/lftruncate.c @@ -0,0 +1,104 @@ +/* lftruncate.c - lftruncate */ + +#include + +/*------------------------------------------------------------------------ + * lftruncate - Truncate a file by freeing its index and data blocks + * (assumes directory mutex held) + *------------------------------------------------------------------------ + */ +status lftruncate ( + struct lflcblk *lfptr /* Ptr to file's cntl blk entry */ + ) +{ + struct ldentry *ldptr; /* Pointer to file's dir. entry */ + struct lfiblk iblock; /* Buffer for one index block */ + ibid32 ifree; /* Start of index blk free list */ + ibid32 firstib; /* First index blk of the file */ + ibid32 nextib; /* Walks down list of the */ + /* file's index blocks */ + dbid32 nextdb; /* Next data block to free */ + int32 i; /* Moves through data blocks in */ + /* a given index block */ + + ldptr = lfptr->lfdirptr; /* Get pointer to dir. entry */ + if (ldptr->ld_size == 0) { /* File is already empty */ + return OK; + } + + /* Clean up the open local file first */ + + if ( (lfptr->lfibdirty) || (lfptr->lfdbdirty) ) { + lfflush(lfptr); + } + lfptr->lfpos = 0; + lfptr->lfinum = LF_INULL; + lfptr->lfdnum = LF_DNULL; + lfptr->lfbyte = &lfptr->lfdblock[LF_BLKSIZ]; + + /* Obtain ID of first index block on free list */ + + ifree = Lf_data.lf_dir.lfd_ifree; + + /* Record file's first i-block and clear directory entry */ + + firstib = ldptr->ld_ilist; + ldptr->ld_ilist = LF_INULL; + ldptr->ld_size = 0; + Lf_data.lf_dirdirty = TRUE; + + /* Walk along index block list, disposing of each data block */ + /* and clearing the corresponding pointer. A note on loop */ + /* termination: last pointer is set to ifree below. */ + + for (nextib=firstib; nextib!=ifree; nextib=iblock.ib_next) { + + /* Obtain a copy of current index block from disk */ + + lfibget(Lf_data.lf_dskdev, nextib, &iblock); + + /* Free each data block in the index block */ + + for (i=0; i + +/*------------------------------------------------------------------------ + * mount - Add a prefix mapping to the name space + *------------------------------------------------------------------------ + */ +syscall mount( + char *prefix, /* Prefix to add */ + char *replace, /* Replacement string */ + did32 device /* Device ID to use */ +) +{ + intmask mask; /* Saved interrupt mask */ + struct nmentry *namptr; /* Pointer to unused table entry*/ + int32 psiz, rsiz; /* Sizes of prefix & replacement*/ + int32 i; /* Counter for copy loop */ + + mask = disable(); + + psiz = namlen(prefix, NM_PRELEN); + rsiz = namlen(replace, NM_REPLLEN); + + /* If arguments are invalid or table is full, return error */ + + if ( (psiz == SYSERR) || (rsiz == SYSERR) || + (isbaddev(device)) || (nnames >= NNAMES) ) { + restore(mask); + return SYSERR; + } + + /* Allocate a slot in the table */ + + namptr = &nametab[nnames]; /* Next unused entry in table */ + + /* copy prefix and replacement strings and record device ID */ + + for (i=0; inprefix[i] = *prefix++; + } + + for (i=0; inreplace[i] = *replace++; + } + + namptr->ndevice = device; /* Record the device ID */ + + nnames++; /* Increment number of names */ + + restore(mask); + return OK; +} + + +/*------------------------------------------------------------------------ + * namlen - Compute the length of a string stopping at maxlen + *------------------------------------------------------------------------ + */ +int32 namlen( + char *name, /* Name to use */ + int32 maxlen /* Maximum length (including a */ + /* NULLCH) */ +) +{ + int32 i; /* Count of characters found */ + + /* Search until a null terminator or length reaches max */ + + for (i=0; i < maxlen; i++) { + if (*name++ == NULLCH) { + return i+1; /* Include NULLCH in length */ + } + } + return SYSERR; +} diff --git a/device/x86-galileo/nam/naminit.c b/device/x86-galileo/nam/naminit.c new file mode 100644 index 0000000..df8641b --- /dev/null +++ b/device/x86-galileo/nam/naminit.c @@ -0,0 +1,91 @@ +/* naminit.c - naminit */ + +#include + +#ifndef RFILESYS +#define RFILESYS SYSERR +#endif + +#ifndef FILESYS +#define FILESYS SYSERR +#endif + +#ifndef LFILESYS +#define LFILESYS SYSERR +#endif + +struct nmentry nametab[NNAMES]; /* Table of name mappings */ +int32 nnames; /* Number of entries allocated */ + +/*------------------------------------------------------------------------ + * naminit - Initialize the syntactic namespace + *------------------------------------------------------------------------ + */ +status naminit(void) +{ + did32 i; /* Index into devtab */ + struct dentry *devptr; /* Pointer to device table entry*/ + char tmpstr[NM_MAXLEN]; /* String to hold a name */ + status retval; /* Return value */ + char *tptr; /* Pointer into tempstring */ + char *nptr; /* Pointer to device name */ + char devprefix[] = "/dev/"; /* Prefix to use for devices */ + int32 len; /* Length of created name */ + char ch; /* Storage for a character */ + + /* Set prefix table to empty */ + + nnames = 0; + + for (i=0; idvname; /* Move to device name */ + + /* Map device name to lower case and append */ + + while(++len < NM_MAXLEN) { + ch = *nptr++; + if ( (ch >= 'A') && (ch <= 'Z')) { + ch += 'a' - 'A'; + } + if ( (*tptr++ = ch) == NULLCH) { + break; + } + } + + if (len > NM_MAXLEN) { + kprintf("namespace: device name %s too long\r\n", + devptr->dvname); + continue; + } + + retval = mount(tmpstr, NULLSTR, devptr->dvnum); + if (retval == SYSERR) { + kprintf("namespace: cannot mount device %d\r\n", + devptr->dvname); + continue; + } + } + + /* Add other prefixes (longest prefix first) */ + + mount("/dev/null", "", NULLDEV); + mount("/remote/", "remote:", RFILESYS); + mount("/local/", NULLSTR, LFILESYS); + mount("/dev/", NULLSTR, SYSERR); + mount("~/", NULLSTR, LFILESYS); + mount("/", "root:", RFILESYS); + mount("", "", LFILESYS); + + return OK; +} diff --git a/device/x86-galileo/nam/nammap.c b/device/x86-galileo/nam/nammap.c new file mode 100644 index 0000000..be8b255 --- /dev/null +++ b/device/x86-galileo/nam/nammap.c @@ -0,0 +1,135 @@ +/* nammap.c - nammap, namrepl, namcpy */ + +#include + +status namcpy(char *, char *, int32); +did32 namrepl(char *, char[]); + +/*------------------------------------------------------------------------ + * nammap - Using namespace, map name to new name and new device + *------------------------------------------------------------------------ + */ +devcall nammap( + char *name, /* The name to map */ + char newname[NM_MAXLEN], /* Buffer for mapped name */ + did32 namdev /* ID of the namespace device */ + ) +{ + did32 newdev; /* Device descriptor to return */ + char tmpname[NM_MAXLEN]; /* Temporary buffer for name */ + int32 iter; /* Number of iterations */ + + /* Place original name in temporary buffer and null terminate */ + + if (namcpy(tmpname, name, NM_MAXLEN) == SYSERR) { + return SYSERR; + } + + /* Repeatedly substitute the name prefix until a non-namespace */ + /* device is reached or an iteration limit is exceeded */ + + for (iter=0; iternprefix; /* Start at beginning of prefix */ + + /* Compare prefix to string and count prefix size */ + + for (plen=0; *pptr != NULLCH ; plen++) { + if (*pptr != *optr) { + break; + } + pptr++; + optr++; + } + if (*pptr != NULLCH) { /* Prefix does not match */ + continue; + } + + /* Found a match - check that replacement string plus */ + /* bytes remaining at the end of the original name will */ + /* fit into new name buffer. Ignore null on replacement*/ + /* string, but keep null on remainder of name. */ + + olen = namlen(name ,NM_MAXLEN); + rlen = namlen(namptr->nreplace,NM_MAXLEN) - 1; + remain = olen - plen; + if ( (rlen + remain) > NM_MAXLEN) { + return (did32)SYSERR; + } + + /* Place replacement string followed by remainder of */ + /* original name (and null) into the new name buffer */ + + + nptr = newname; + rptr = namptr->nreplace; + for (; rlen>0 ; rlen--) { + *nptr++ = *rptr++; + } + for (; remain>0 ; remain--) { + *nptr++ = *optr++; + } + return namptr->ndevice; + } + return (did32)SYSERR; +} + +/*------------------------------------------------------------------------ + * namcpy - Copy a name from one buffer to another, checking length + *------------------------------------------------------------------------ + */ +status namcpy( + char *newname, /* Buffer to hold copy */ + char *oldname, /* Buffer containing name */ + int32 buflen /* Size of buffer for copy */ + ) +{ + char *nptr; /* Point to new name */ + char *optr; /* Point to old name */ + int32 cnt; /* Count of characters copied */ + + nptr = newname; + optr = oldname; + + for (cnt=0; cnt + +/*------------------------------------------------------------------------ + * namopen - Open a file or device based on the name + *------------------------------------------------------------------------ + */ +devcall namopen( + struct dentry *devptr, /* Entry in device switch table */ + char *name, /* Name to open */ + char *mode /* Mode argument */ + ) +{ + char newname[NM_MAXLEN]; /* Name with prefix replaced */ + did32 newdev; /* Device ID after mapping */ + + /* Use namespace to map name to a new name and new descriptor */ + + newdev = nammap(name, newname, devptr->dvnum); + + if (newdev == SYSERR) { + return SYSERR; + } + + /* Open underlying device and return status */ + + return open(newdev, newname, mode); +} diff --git a/device/x86-galileo/ram/ramclose.c b/device/x86-galileo/ram/ramclose.c new file mode 100644 index 0000000..0580c07 --- /dev/null +++ b/device/x86-galileo/ram/ramclose.c @@ -0,0 +1,14 @@ +/* ramclose.c - ramclose */ + +#include + +/*------------------------------------------------------------------------ + * Ramclose - Close a ram disk + *------------------------------------------------------------------------ + */ +devcall ramclose ( + struct dentry *devptr /* Entry in device switch table */ + ) +{ + return OK; +} diff --git a/device/x86-galileo/ram/raminit.c b/device/x86-galileo/ram/raminit.c new file mode 100644 index 0000000..866140e --- /dev/null +++ b/device/x86-galileo/ram/raminit.c @@ -0,0 +1,19 @@ +/* raminit.c - raminit */ + +#include +#include + +struct ramdisk Ram; + +/*------------------------------------------------------------------------ + * raminit - Initialize the remote disk system device + *------------------------------------------------------------------------ + */ +devcall raminit ( + struct dentry *devptr /* Entry in device switch table */ + ) +{ + memcpy(Ram.disk, "hopeless", 8); + memcpy( &Ram.disk[8], Ram.disk, RM_BLKSIZ * RM_BLKS - 8); + return OK; +} diff --git a/device/x86-galileo/ram/ramopen.c b/device/x86-galileo/ram/ramopen.c new file mode 100644 index 0000000..07ba1ba --- /dev/null +++ b/device/x86-galileo/ram/ramopen.c @@ -0,0 +1,19 @@ +/* ramopen.c - ramopen */ + +#include + +/*------------------------------------------------------------------------ + * ramopen - Open a ram disk + *------------------------------------------------------------------------ + */ + +devcall ramopen ( + struct dentry *devptr, /* Entry in device switch table */ + char *name, /* Unused for a ram disk */ + char *mode /* Unused for a ram disk */ + ) +{ + /* No action -- just return the device descriptor */ + + return devptr->dvnum; +} diff --git a/device/x86-galileo/ram/ramread.c b/device/x86-galileo/ram/ramread.c new file mode 100644 index 0000000..07b8fbf --- /dev/null +++ b/device/x86-galileo/ram/ramread.c @@ -0,0 +1,21 @@ +/* ramread.c - ramread */ + +#include +#include + +/*------------------------------------------------------------------------ + * ramread - Read a block from a ram disk + *------------------------------------------------------------------------ + */ +devcall ramread ( + struct dentry *devptr, /* Entry in device switch table */ + char *buff, /* Buffer to hold disk block */ + int32 blk /* Block number of block to read*/ + ) +{ + int32 bpos; /* Byte position of blk */ + + bpos = RM_BLKSIZ * blk; + memcpy(buff, &Ram.disk[bpos], RM_BLKSIZ); + return OK; +} diff --git a/device/x86-galileo/ram/ramwrite.c b/device/x86-galileo/ram/ramwrite.c new file mode 100644 index 0000000..3b5f19a --- /dev/null +++ b/device/x86-galileo/ram/ramwrite.c @@ -0,0 +1,21 @@ +/* ramwrite.c - ramwrite */ + +#include +#include + +/*------------------------------------------------------------------------ + * ramwrite - Write a block to a ram disk + *------------------------------------------------------------------------ + */ +devcall ramwrite ( + struct dentry *devptr, /* Entry in device switch table */ + char *buff, /* Buffer containing a block */ + int32 blk /* Block number to write */ + ) +{ + int32 bpos; /* Byte position of blk */ + + bpos = RM_BLKSIZ * blk; + memcpy(&Ram.disk[bpos], buff, RM_BLKSIZ); + return OK; +} diff --git a/device/x86-galileo/rds/TODO b/device/x86-galileo/rds/TODO new file mode 100644 index 0000000..d7d0205 --- /dev/null +++ b/device/x86-galileo/rds/TODO @@ -0,0 +1,5 @@ + + + +rdsbufalloc.c +rdsprocess.c diff --git a/device/x86-galileo/rds/rdsbufalloc.c b/device/x86-galileo/rds/rdsbufalloc.c new file mode 100644 index 0000000..b872e07 --- /dev/null +++ b/device/x86-galileo/rds/rdsbufalloc.c @@ -0,0 +1,50 @@ +/* rdsbufalloc.c - rdsbufalloc */ + +#include + +/*------------------------------------------------------------------------ + * rdsbufalloc - Allocate a buffer from the free list or the cache + *------------------------------------------------------------------------ + */ +struct rdbuff *rdsbufalloc ( + struct rdscblk *rdptr /* Ptr to device control block */ + ) +{ + struct rdbuff *bptr; /* Pointer to a buffer */ + struct rdbuff *pptr; /* Pointer to previous buffer */ + struct rdbuff *nptr; /* Pointer to next buffer */ + + /* Wait for an available buffer */ + + wait(rdptr->rd_availsem); + + /* If free list contains a buffer, extract it */ + + bptr = rdptr->rd_free; + + if ( bptr != (struct rdbuff *)NULL ) { + rdptr->rd_free = bptr->rd_next; + return bptr; + } + + /* Extract oldest item in cache that has ref count zero (at */ + /* least one such entry must exist because the semaphore */ + /* had a nonzero count) */ + + bptr = rdptr->rd_ctprev; + while (bptr != (struct rdbuff *) &rdptr->rd_chnext) { + if (bptr->rd_refcnt <= 0) { + + /* Remove from cache and return to caller */ + + pptr = bptr->rd_prev; + nptr = bptr->rd_next; + pptr->rd_next = nptr; + nptr->rd_prev = pptr; + return bptr; + } + bptr = bptr->rd_prev; + } + panic("Remote disk cannot find an available buffer"); + return (struct rdbuff *)SYSERR; +} diff --git a/device/x86-galileo/rds/rdsclose.c b/device/x86-galileo/rds/rdsclose.c new file mode 100644 index 0000000..eeac7e5 --- /dev/null +++ b/device/x86-galileo/rds/rdsclose.c @@ -0,0 +1,60 @@ +/* rdsclose.c - rdsclose */ + +#include + +/*------------------------------------------------------------------------ + * rdsclose - Close a remote disk device + *------------------------------------------------------------------------ + */ +devcall rdsclose ( + struct dentry *devptr /* Entry in device switch table */ + ) +{ + struct rdscblk *rdptr; /* Ptr to control block entry */ + struct rdbuff *bptr; /* Ptr to buffer on a list */ + struct rdbuff *nptr; /* Ptr to next buff on the list */ + int32 nmoved; /* Number of buffers moved */ + + /* Device must be open */ + + rdptr = &rdstab[devptr->dvminor]; + if (rdptr->rd_state != RD_OPEN) { + return SYSERR; + } + + /* Request queue must be empty */ + + if (rdptr->rd_rhnext != (struct rdbuff *)&rdptr->rd_rtnext) { + return SYSERR; + } + + /* Move all buffers from the cache to the free list */ + + bptr = rdptr->rd_chnext; + nmoved = 0; + while (bptr != (struct rdbuff *)&rdptr->rd_ctnext) { + nmoved++; + + /* Unlink buffer from cache */ + + nptr = bptr->rd_next; + (bptr->rd_prev)->rd_next = nptr; + nptr->rd_prev = bptr->rd_prev; + + /* Insert buffer into free list */ + + bptr->rd_next = rdptr->rd_free; + + rdptr->rd_free = bptr; + bptr->rd_status = RD_INVALID; + + /* Move to next buffer in the cache */ + + bptr = nptr; + } + + /* Set the state to indicate the device is closed */ + + rdptr->rd_state = RD_FREE; + return OK; +} diff --git a/device/x86-galileo/rds/rdscomm.c b/device/x86-galileo/rds/rdscomm.c new file mode 100644 index 0000000..d9e13ae --- /dev/null +++ b/device/x86-galileo/rds/rdscomm.c @@ -0,0 +1,114 @@ +/* rdscomm.c - rdscomm */ + +#include + +/*------------------------------------------------------------------------ + * rdscomm - handle communication with a remote disk server (send a + * request and receive a reply, including sequencing and + * retries) + *------------------------------------------------------------------------ + */ +status rdscomm ( + struct rd_msg_hdr *msg, /* Message to send */ + int32 mlen, /* Message length */ + struct rd_msg_hdr *reply, /* Buffer for reply */ + int32 rlen, /* Size of reply buffer */ + struct rdscblk *rdptr /* Ptr to device control block */ + ) +{ + int32 i; /* Counts retries */ + int32 retval; /* Return value */ + int32 seq; /* Sequence for this exchange */ + uint32 localip; /* Local IP address */ + int16 rtype; /* Reply type in host byte order*/ + bool8 xmit; /* Should we transmit again? */ + int32 slot; /* UDP slot */ + + /* For the first time after reboot, register the server port */ + + if ( ! rdptr->rd_registered ) { + slot = udp_register(0, rdptr->rd_ser_port, + rdptr->rd_loc_port); + if(slot == SYSERR) { + return SYSERR; + } + rdptr->rd_udpslot = slot; + rdptr->rd_registered = TRUE; + } + + if ( NetData.ipvalid == FALSE ) { + localip = getlocalip(); + if((int32)localip == SYSERR) { + return SYSERR; + } + } + + /* Retrieve the saved UDP slot number */ + + slot = rdptr->rd_udpslot; + + /* Assign message next sequence number */ + + seq = rdptr->rd_seq++; + msg->rd_seq = htonl(seq); + + /* Repeat RD_RETRIES times: send message and receive reply */ + + xmit = TRUE; + for (i=0; ird_ser_ip, rdptr->rd_ser_port, + (char *)msg, mlen); + if (retval == SYSERR) { + kprintf("Cannot send to remote disk server\n\r"); + return SYSERR; + } + } else { + xmit = TRUE; + } + + /* Receive a reply */ + + retval = udp_recv(slot, (char *)reply, rlen, + RD_TIMEOUT); + + if (retval == TIMEOUT) { + continue; + } else if (retval == SYSERR) { + kprintf("Error reading remote disk reply\n\r"); + return SYSERR; + } + + /* Verify that sequence in reply matches request */ + + + if (ntohl(reply->rd_seq) < seq) { + xmit = FALSE; + } else if (ntohl(reply->rd_seq) != seq) { + continue; + } + + /* Verify the type in the reply matches the request */ + + rtype = ntohs(reply->rd_type); + if (rtype != ( ntohs(msg->rd_type) | RD_MSG_RESPONSE) ) { + continue; + } + + /* Check the status */ + + if (ntohs(reply->rd_status) != 0) { + return SYSERR; + } + + return OK; + } + + /* Retries exhausted without success */ + + kprintf("Timeout on exchange with remote disk server\n\r"); + return TIMEOUT; +} diff --git a/device/x86-galileo/rds/rdscontrol.c b/device/x86-galileo/rds/rdscontrol.c new file mode 100644 index 0000000..41314c9 --- /dev/null +++ b/device/x86-galileo/rds/rdscontrol.c @@ -0,0 +1,118 @@ +/* rdscontrol.c - rdscontrol */ + +#include + +/*------------------------------------------------------------------------ + * rdscontrol - Provide control functions for the remote disk + *------------------------------------------------------------------------ + */ +devcall rdscontrol ( + struct dentry *devptr, /* Entry in device switch table */ + int32 func, /* The control function to use */ + int32 arg1, /* Argument #1 */ + int32 arg2 /* Argument #2 */ + ) +{ + struct rdscblk *rdptr; /* Pointer to control block */ + struct rdbuff *bptr; /* Ptr to buffer that will be */ + /* placed on the req. queue */ + struct rdbuff *pptr; /* Ptr to "previous" node on */ + /* a list */ + struct rd_msg_dreq msg; /* Buffer for delete request */ + struct rd_msg_dres resp; /* Buffer for delete response */ + char *to, *from; /* Used during name copy */ + int32 retval; /* Return value */ + + /* Verify that device is currently open */ + + rdptr = &rdstab[devptr->dvminor]; + if (rdptr->rd_state != RD_OPEN) { + return SYSERR; + } + + switch (func) { + + /* Synchronize writes */ + + case RDS_CTL_SYNC: + + /* Allocate a buffer to use for the request list */ + + bptr = rdsbufalloc(rdptr); + if (bptr == (struct rdbuff *)SYSERR) { + return SYSERR; + } + + /* Form a sync request */ + + bptr->rd_op = RD_OP_SYNC; + bptr->rd_refcnt = 1; + bptr->rd_blknum = 0; /* Unused */ + bptr->rd_status = RD_INVALID; + bptr->rd_pid = getpid(); + + /* Insert new request into list just before tail */ + + pptr = rdptr->rd_rtprev; + rdptr->rd_rtprev = bptr; + bptr->rd_next = pptr->rd_next; + bptr->rd_prev = pptr; + pptr->rd_next = bptr; + + /* Prepare to wait until item is processed */ + + recvclr(); + resume(rdptr->rd_comproc); + + /* Block to wait for message */ + + bptr = (struct rdbuff *)receive(); + break; + + /* Delete the remote disk (entirely remove it) */ + + case RDS_CTL_DEL: + + /* Handcraft a message for the server that requests */ + /* deleting the disk with the specified ID */ + + msg.rd_type = htons(RD_MSG_DREQ);/* Request deletion */ + msg.rd_status = htons(0); + msg.rd_seq = 0; /* rdscomm will insert sequence # later */ + to = msg.rd_id; + memset(to, NULLCH, RD_IDLEN); /* Initialize to zeroes */ + from = rdptr->rd_id; + while ( (*to++ = *from++) != NULLCH ) { /* copy ID */ + ; + } + + /* Send message and receive response */ + + retval = rdscomm((struct rd_msg_hdr *)&msg, + sizeof(struct rd_msg_dreq), + (struct rd_msg_hdr *)&resp, + sizeof(struct rd_msg_dres), + rdptr); + + /* Check response */ + + if (retval == SYSERR) { + return SYSERR; + } else if (retval == TIMEOUT) { + kprintf("Timeout during remote file delete\n\r"); + return SYSERR; + } else if (ntohs(resp.rd_status) != 0) { + return SYSERR; + } + + /* Close local device */ + + return rdsclose(devptr); + + default: + kprintf("rfsControl: function %d not valid\n\r", func); + return SYSERR; + } + + return OK; +} diff --git a/device/x86-galileo/rds/rdsinit.c b/device/x86-galileo/rds/rdsinit.c new file mode 100644 index 0000000..b06533c --- /dev/null +++ b/device/x86-galileo/rds/rdsinit.c @@ -0,0 +1,104 @@ +/* rdsinit.c - rdsinit */ + +#include + +struct rdscblk rdstab[Nrds]; + +/*------------------------------------------------------------------------ + * rdsinit - Initialize the remote disk system device + *------------------------------------------------------------------------ + */ +devcall rdsinit ( + struct dentry *devptr /* Entry in device switch table */ + ) +{ + struct rdscblk *rdptr; /* Ptr to device contol block */ + struct rdbuff *bptr; /* Ptr to buffer in memory */ + /* used to form linked list */ + struct rdbuff *pptr; /* Ptr to previous buff on list */ + struct rdbuff *buffend; /* Last address in buffer memory*/ + uint32 size; /* Total size of memory needed */ + /* buffers */ + + /* Obtain address of control block */ + + rdptr = &rdstab[devptr->dvminor]; + + /* Set control block to unused */ + + rdptr->rd_state = RD_FREE; + rdptr->rd_id[0] = NULLCH; + + /* Set initial message sequence number */ + + rdptr->rd_seq = 1; + + /* Initialize request queue and cache to empty */ + + rdptr->rd_rhnext = (struct rdbuff *) &rdptr->rd_rtnext; + rdptr->rd_rhprev = (struct rdbuff *)NULL; + + rdptr->rd_rtnext = (struct rdbuff *)NULL; + rdptr->rd_rtprev = (struct rdbuff *) &rdptr->rd_rhnext; + + + rdptr->rd_chnext = (struct rdbuff *) &rdptr->rd_ctnext; + rdptr->rd_chprev = (struct rdbuff *)NULL; + + rdptr->rd_ctnext = (struct rdbuff *)NULL; + rdptr->rd_ctprev = (struct rdbuff *) &rdptr->rd_chnext; + + /* Allocate memory for a set of buffers (actually request */ + /* blocks and link them to form the initial free list */ + + size = sizeof(struct rdbuff) * RD_BUFFS; + + bptr = (struct rdbuff *)getmem(size); + rdptr->rd_free = bptr; + + if ((int32)bptr == SYSERR) { + panic("Cannot allocate memory for remote disk buffers"); + } + + buffend = (struct rdbuff *) ((char *)bptr + size); + while (bptr < buffend) { /* walk through memory */ + pptr = bptr; + bptr = (struct rdbuff *) + (sizeof(struct rdbuff)+ (char *)bptr); + pptr->rd_status = RD_INVALID; /* Buffer is empty */ + pptr->rd_next = bptr; /* Point to next buffer */ + } + pptr->rd_next = (struct rdbuff *) NULL; /* Last buffer on list */ + + /* Create the request list and available buffer semaphores */ + + rdptr->rd_availsem = semcreate(RD_BUFFS); + rdptr->rd_reqsem = semcreate(0); + + /* Set the server IP address, server port, and local port */ + + if ( dot2ip(RD_SERVER_IP, &rdptr->rd_ser_ip) == SYSERR ) { + panic("invalid IP address for remote disk server"); + } + + /* Set the port numbers */ + + rdptr->rd_ser_port = RD_SERVER_PORT; + rdptr->rd_loc_port = RD_LOC_PORT + devptr->dvminor; + + /* Specify that the server port is not yet registered */ + + rdptr->rd_registered = FALSE; + + /* Create a communication process */ + + rdptr->rd_comproc = create(rdsprocess, RD_STACK, RD_PRIO, + "rdsproc", 1, rdptr); + + if (rdptr->rd_comproc == SYSERR) { + panic("Cannot create remote disk process"); + } + resume(rdptr->rd_comproc); + + return OK; +} diff --git a/device/x86-galileo/rds/rdsopen.c b/device/x86-galileo/rds/rdsopen.c new file mode 100644 index 0000000..67ee955 --- /dev/null +++ b/device/x86-galileo/rds/rdsopen.c @@ -0,0 +1,93 @@ +/* rdsopen.c - rdsopen */ + +#include + +/*------------------------------------------------------------------------ + * rdsopen - Open a remote disk device and specify an ID to use + *------------------------------------------------------------------------ + */ + +devcall rdsopen ( + struct dentry *devptr, /* Entry in device switch table */ + char *diskid, /* Disk ID to use */ + char *mode /* Unused for a remote disk */ + ) +{ + struct rdscblk *rdptr; /* Ptr to control block entry */ + struct rd_msg_oreq msg; /* Message to be sent */ + struct rd_msg_ores resp; /* Buffer to hold response */ + int32 retval; /* Return value from rdscomm */ + int32 len; /* Counts chars in diskid */ + char *idto; /* Ptr to ID string copy */ + char *idfrom; /* Pointer into ID string */ + + rdptr = &rdstab[devptr->dvminor]; + + /* Reject if device is already open */ + + if (rdptr->rd_state != RD_FREE) { + return SYSERR; + } + rdptr->rd_state = RD_PEND; + + /* Copy disk ID into free table slot */ + + idto = rdptr->rd_id; + idfrom = diskid; + len = 0; + while ( (*idto++ = *idfrom++) != NULLCH) { + len++; + if (len >= RD_IDLEN) { /* ID string is too long */ + return SYSERR; + } + } + + /* Verify that name is non-null */ + + if (len == 0) { + return SYSERR; + } + + /* Hand-craft an open request message to be sent to the server */ + + msg.rd_type = htons(RD_MSG_OREQ);/* Request an open */ + msg.rd_status = htons(0); + msg.rd_seq = 0; /* Rdscomm fills in an entry */ + idto = msg.rd_id; + memset(idto, NULLCH, RD_IDLEN);/* initialize ID to zero bytes */ + + idfrom = diskid; + while ( (*idto++ = *idfrom++) != NULLCH ) { /* Copy ID to req. */ + ; + } + + /* Send message and receive response */ + + retval = rdscomm((struct rd_msg_hdr *)&msg, + sizeof(struct rd_msg_oreq), + (struct rd_msg_hdr *)&resp, + sizeof(struct rd_msg_ores), + rdptr ); + + /* Check response */ + + if (retval == SYSERR) { + rdptr->rd_state = RD_FREE; + return SYSERR; + } else if (retval == TIMEOUT) { + kprintf("Timeout during remote file open\n\r"); + rdptr->rd_state = RD_FREE; + return SYSERR; + } else if (ntohs(resp.rd_status) != 0) { + rdptr->rd_state = RD_FREE; + return SYSERR; + } + + /* Change state of device to indicate currently open */ + + rdptr->rd_state = RD_OPEN; + + /* Return device descriptor */ + + return devptr->dvnum; +} diff --git a/device/x86-galileo/rds/rdsprocess.c b/device/x86-galileo/rds/rdsprocess.c new file mode 100644 index 0000000..33100e5 --- /dev/null +++ b/device/x86-galileo/rds/rdsprocess.c @@ -0,0 +1,207 @@ +/* rdsprocess.c - rdsprocess */ + +#include + +/*------------------------------------------------------------------------ + * rdsprocess - High-priority background process to repeatedly extract + * an item from the request queue and send the request to + * the remote disk server + *------------------------------------------------------------------------ + */ +void rdsprocess ( + struct rdscblk *rdptr /* Ptr to device control block */ + ) +{ + struct rd_msg_wreq msg; /* Message to be sent */ + /* (includes data area) */ + struct rd_msg_rres resp; /* Buffer to hold response */ + /* (includes data area) */ + int32 retval; /* Return value from rdscomm */ + char *idto; /* Ptr to ID string copy */ + char *idfrom; /* Ptr into ID string */ + struct rdbuff *bptr; /* Ptr to buffer at the head of */ + /* the request queue */ + struct rdbuff *nptr; /* Ptr to next buffer on the */ + /* request queue */ + struct rdbuff *pptr; /* Ptr to previous buffer */ + struct rdbuff *qptr; /* Ptr that runs along the */ + /* request queue */ + int32 i; /* Loop index */ + + while (TRUE) { /* Do forever */ + + /* Wait until the request queue contains a node */ + wait(rdptr->rd_reqsem); + bptr = rdptr->rd_rhnext; + + /* Use operation in request to determine action */ + + switch (bptr->rd_op) { + + case RD_OP_READ: + + /* Build a read request message for the server */ + + msg.rd_type = htons(RD_MSG_RREQ); /* Read request */ + msg.rd_status = htons(0); + msg.rd_seq = 0; /* Rdscomm fills in an entry */ + idto = msg.rd_id; + memset(idto, NULLCH, RD_IDLEN);/* Initialize ID to zero */ + idfrom = rdptr->rd_id; + while ( (*idto++ = *idfrom++) != NULLCH ) { /* Copy ID */ + ; + } + + /* Send the message and receive a response */ + + retval = rdscomm((struct rd_msg_hdr *)&msg, + sizeof(struct rd_msg_rreq), + (struct rd_msg_hdr *)&resp, + sizeof(struct rd_msg_rres), + rdptr ); + + /* Check response */ + + if ( (retval == SYSERR) || (retval == TIMEOUT) || + (ntohs(resp.rd_status) != 0) ) { + panic("Failed to contact remote disk server"); + } + + /* Copy data from the reply into the buffer */ + + for (i=0; ird_block[i] = resp.rd_data[i]; + } + + /* Unlink buffer from the request queue */ + + nptr = bptr->rd_next; + pptr = bptr->rd_prev; + nptr->rd_prev = bptr->rd_prev; + pptr->rd_next = bptr->rd_next; + + /* Insert buffer in the cache */ + + pptr = (struct rdbuff *) &rdptr->rd_chnext; + nptr = pptr->rd_next; + bptr->rd_next = nptr; + bptr->rd_prev = pptr; + pptr->rd_next = bptr; + nptr->rd_prev = bptr; + + /* Initialize reference count */ + + bptr->rd_refcnt = 1; + + /* Signal the available semaphore */ + + signal(rdptr->rd_availsem); + + /* Send a message to waiting process */ + + send(bptr->rd_pid, (uint32)bptr); + + /* If other processes are waiting to read the */ + /* block, notify them and remove the request */ + + qptr = rdptr->rd_rhnext; + while (qptr != (struct rdbuff *)&rdptr->rd_rtnext) { + if (qptr->rd_blknum == bptr->rd_blknum) { + bptr->rd_refcnt++; + send(qptr->rd_pid,(uint32)bptr); + + /* Unlink request from queue */ + + pptr = qptr->rd_prev; + nptr = qptr->rd_next; + pptr->rd_next = bptr->rd_next; + nptr->rd_prev = bptr->rd_prev; + + /* Move buffer to the free list */ + + qptr->rd_next = rdptr->rd_free; + rdptr->rd_free = qptr; + signal(rdptr->rd_availsem); + break; + } + qptr = qptr->rd_next; + } + break; + + case RD_OP_WRITE: + + /* Build a write request message for the server */ + + msg.rd_type = htons(RD_MSG_WREQ); /* Write request*/ + msg.rd_blk = bptr->rd_blknum; + msg.rd_status = htons(0); + msg.rd_seq = 0; /* Rdscomb fills in an entry */ + idto = msg.rd_id; + memset(idto, NULLCH, RD_IDLEN);/* Initialize ID to zero */ + idfrom = rdptr->rd_id; + while ( (*idto++ = *idfrom++) != NULLCH ) { /* Copy ID */ + ; + } + for (i=0; ird_block[i]; + } + + /* Unlink buffer from request queue */ + + nptr = bptr->rd_next; + pptr = bptr->rd_prev; + pptr->rd_next = nptr; + nptr->rd_prev = pptr; + + /* Insert buffer in the cache */ + + pptr = (struct rdbuff *) &rdptr->rd_chnext; + nptr = pptr->rd_next; + bptr->rd_next = nptr; + bptr->rd_prev = pptr; + pptr->rd_next = bptr; + nptr->rd_prev = bptr; + + /* Declare that buffer is eligible for reuse */ + + bptr->rd_refcnt = 0; + signal(rdptr->rd_availsem); + + /* Send the message and receive a response */ + + retval = rdscomm((struct rd_msg_hdr *)&msg, + sizeof(struct rd_msg_wreq), + (struct rd_msg_hdr *)&resp, + sizeof(struct rd_msg_wres), + rdptr ); + + /* Check response */ + + if ( (retval == SYSERR) || (retval == TIMEOUT) || + (ntohs(resp.rd_status) != 0) ) { + panic("failed to contact remote disk server"); + } + break; + + case RD_OP_SYNC: + + /* Send a message to the waiting process */ + + send(bptr->rd_pid, OK); + + /* Unlink buffer from the request queue */ + + nptr = bptr->rd_next; + pptr = bptr->rd_prev; + nptr->rd_prev = bptr->rd_prev; + pptr->rd_next = bptr->rd_next; + + /* Insert buffer into the free list */ + + bptr->rd_next = rdptr->rd_free; + rdptr->rd_free = bptr; + signal(rdptr->rd_availsem); + break; + } + } +} diff --git a/device/x86-galileo/rds/rdsread.c b/device/x86-galileo/rds/rdsread.c new file mode 100644 index 0000000..b4c62eb --- /dev/null +++ b/device/x86-galileo/rds/rdsread.c @@ -0,0 +1,123 @@ +/* rdsread.c - rdsread */ + +#include + +/*------------------------------------------------------------------------ + * rdsread - Read a block from a remote disk + *------------------------------------------------------------------------ + */ +devcall rdsread ( + struct dentry *devptr, /* Entry in device switch table */ + char *buff, /* Buffer to hold disk block */ + int32 blk /* Block number of block to read*/ + ) +{ + struct rdscblk *rdptr; /* Pointer to control block */ + struct rdbuff *bptr; /* Pointer to buffer possibly */ + /* in the request list */ + struct rdbuff *nptr; /* Pointer to "next" node on a */ + /* list */ + struct rdbuff *pptr; /* Pointer to "previous" node */ + /* on a list */ + struct rdbuff *cptr; /* Pointer that walks the cache */ + + /* If device not currently in use, report an error */ + + rdptr = &rdstab[devptr->dvminor]; + if (rdptr->rd_state != RD_OPEN) { + return SYSERR; + } + + /* Search the cache for specified block */ + + bptr = rdptr->rd_chnext; + while (bptr != (struct rdbuff *)&rdptr->rd_ctnext) { + if (bptr->rd_blknum == blk) { + if (bptr->rd_status == RD_INVALID) { + break; + } + memcpy(buff, bptr->rd_block, RD_BLKSIZ); + return OK; + } + bptr = bptr->rd_next; + } + + /* Search the request list for most recent occurrence of block */ + + bptr = rdptr->rd_rtprev; /* Start at tail of list */ + + while (bptr != (struct rdbuff *)&rdptr->rd_rhnext) { + if (bptr->rd_blknum == blk) { + + /* If most recent request for block is write, copy data */ + + if (bptr->rd_op == RD_OP_WRITE) { + memcpy(buff, bptr->rd_block, RD_BLKSIZ); + return OK; + } + break; + } + bptr = bptr->rd_prev; + } + + /* Allocate a buffer and add read request to tail of req. queue */ + + bptr = rdsbufalloc(rdptr); + bptr->rd_op = RD_OP_READ; + bptr->rd_refcnt = 1; + bptr->rd_blknum = blk; + bptr->rd_status = RD_INVALID; + bptr->rd_pid = getpid(); + + /* Insert new request into list just before tail */ + + pptr = rdptr->rd_rtprev; + rdptr->rd_rtprev = bptr; + bptr->rd_next = pptr->rd_next; + bptr->rd_prev = pptr; + pptr->rd_next = bptr; + + /* Prepare to receive message when read completes */ + + recvclr(); + + /* Signal semaphore to start communication process */ + + signal(rdptr->rd_reqsem); + + /* Block to wait for message */ + + bptr = (struct rdbuff *)receive(); + if (bptr == (struct rdbuff *)SYSERR) { + return SYSERR; + } + memcpy(buff, bptr->rd_block, RD_BLKSIZ); + bptr->rd_refcnt--; + if (bptr->rd_refcnt <= 0) { + + /* Look for previous item in cache with the same block */ + /* number to see if this item was only being kept */ + /* until pending read completed */ + + cptr = rdptr->rd_chnext; + while (cptr != bptr) { + if (cptr->rd_blknum == blk) { + + /* Unlink from cache */ + + pptr = bptr->rd_prev; + nptr = bptr->rd_next; + pptr->rd_next = nptr; + nptr->rd_prev = pptr; + + /* Add to the free list */ + + bptr->rd_next = rdptr->rd_free; + rdptr->rd_free = bptr; + break; + } + cptr = cptr->rd_next; + } + } + return OK; +} diff --git a/device/x86-galileo/rds/rdswrite.c b/device/x86-galileo/rds/rdswrite.c new file mode 100644 index 0000000..4153a40 --- /dev/null +++ b/device/x86-galileo/rds/rdswrite.c @@ -0,0 +1,91 @@ +/* rdswrite.c - rdswrite */ + +#include + +/*------------------------------------------------------------------------ + * rdswrite - Write a block to a remote disk + *------------------------------------------------------------------------ + */ +devcall rdswrite ( + struct dentry *devptr, /* Entry in device switch table */ + char *buff, /* Buffer that holds a disk blk */ + int32 blk /* Block number to write */ + ) +{ + struct rdscblk *rdptr; /* Pointer to control block */ + struct rdbuff *bptr; /* Pointer to buffer on a list */ + struct rdbuff *pptr; /* Ptr to previous buff on list */ + struct rdbuff *nptr; /* Ptr to next buffer on list */ + bool8 found; /* Was buff found during search?*/ + + /* If device not currently in use, report an error */ + + rdptr = &rdstab[devptr->dvminor]; + if (rdptr->rd_state != RD_OPEN) { + return SYSERR; + } + + /* If request queue already contains a write request */ + /* for the block, replace the contents */ + + bptr = rdptr->rd_rhnext; + while (bptr != (struct rdbuff *)&rdptr->rd_rtnext) { + if ( (bptr->rd_blknum == blk) && + (bptr->rd_op == RD_OP_WRITE) ) { + memcpy(bptr->rd_block, buff, RD_BLKSIZ); + return OK; + } + bptr = bptr->rd_next; + } + + + /* Search cache for cached copy of block */ + + bptr = rdptr->rd_chnext; + found = FALSE; + while (bptr != (struct rdbuff *)&rdptr->rd_ctnext) { + if (bptr->rd_blknum == blk) { + if (bptr->rd_refcnt <= 0) { + pptr = bptr->rd_prev; + nptr = bptr->rd_next; + + /* Unlink node from cache list and reset*/ + /* the available semaphore accordingly*/ + + pptr->rd_next = bptr->rd_next; + nptr->rd_prev = bptr->rd_prev; + semreset(rdptr->rd_availsem, + semcount(rdptr->rd_availsem) - 1); + found = TRUE; + } + break; + } + bptr = bptr->rd_next; + } + + if ( !found ) { + bptr = rdsbufalloc(rdptr); + } + + /* Create a write request */ + + memcpy(bptr->rd_block, buff, RD_BLKSIZ); + bptr->rd_op = RD_OP_WRITE; + bptr->rd_refcnt = 0; + bptr->rd_blknum = blk; + bptr->rd_status = RD_VALID; + bptr->rd_pid = getpid(); + + /* Insert new request into list just before tail */ + + pptr = rdptr->rd_rtprev; + rdptr->rd_rtprev = bptr; + bptr->rd_next = pptr->rd_next; + bptr->rd_prev = pptr; + pptr->rd_next = bptr; + + /* Signal semaphore to start communication process */ + + signal(rdptr->rd_reqsem); + return OK; +} diff --git a/device/x86-galileo/rfs/rflclose.c b/device/x86-galileo/rfs/rflclose.c new file mode 100644 index 0000000..f1f0d87 --- /dev/null +++ b/device/x86-galileo/rfs/rflclose.c @@ -0,0 +1,32 @@ +/* rflclose.c - rflclose */ + +#include + +/*------------------------------------------------------------------------ + * rflclose - Close a remote file device + *------------------------------------------------------------------------ + */ +devcall rflclose ( + struct dentry *devptr /* Entry in device switch table */ + ) +{ + struct rflcblk *rfptr; /* Pointer to control block */ + + /* Wait for exclusive access */ + + wait(Rf_data.rf_mutex); + + /* Verify remote file device is open */ + + rfptr = &rfltab[devptr->dvminor]; + if (rfptr->rfstate == RF_FREE) { + signal(Rf_data.rf_mutex); + return SYSERR; + } + + /* Mark device closed */ + + rfptr->rfstate = RF_FREE; + signal(Rf_data.rf_mutex); + return OK; +} diff --git a/device/x86-galileo/rfs/rflgetc.c b/device/x86-galileo/rfs/rflgetc.c new file mode 100644 index 0000000..3db46c1 --- /dev/null +++ b/device/x86-galileo/rfs/rflgetc.c @@ -0,0 +1,23 @@ +/* rflgetc.c - rflgetc */ + +#include + +/*------------------------------------------------------------------------ + * rflgetc - Read one character from a remote file + *------------------------------------------------------------------------ + */ +devcall rflgetc( + struct dentry *devptr /* Entry in device switch table */ + ) +{ + char ch; /* Character to read */ + int32 retval; /* Return value */ + + retval = rflread(devptr, &ch, 1); + + if (retval != 1) { + return SYSERR; + } + + return (devcall)ch; +} diff --git a/device/x86-galileo/rfs/rflinit.c b/device/x86-galileo/rfs/rflinit.c new file mode 100644 index 0000000..79e43c8 --- /dev/null +++ b/device/x86-galileo/rfs/rflinit.c @@ -0,0 +1,29 @@ +/* rflinit.c - rflinit */ + +#include + +struct rflcblk rfltab[Nrfl]; /* Remote file control blocks */ + +/*------------------------------------------------------------------------ + * rflinit - Initialize a remote file device + *------------------------------------------------------------------------ + */ +devcall rflinit( + struct dentry *devptr /* Entry in device switch table */ + ) +{ + struct rflcblk *rflptr; /* Ptr. to control block entry */ + int32 i; /* Walks through name arrary */ + + rflptr = &rfltab[ devptr->dvminor ]; + + /* Initialize entry to unused */ + + rflptr->rfstate = RF_FREE; + rflptr->rfdev = devptr->dvnum; + for (i=0; irfname[i] = NULLCH; + } + rflptr->rfpos = rflptr->rfmode = 0; + return OK; +} diff --git a/device/x86-galileo/rfs/rflputc.c b/device/x86-galileo/rfs/rflputc.c new file mode 100644 index 0000000..e09290b --- /dev/null +++ b/device/x86-galileo/rfs/rflputc.c @@ -0,0 +1,23 @@ +/* rflputc.c - rflputc */ + +#include + +/*------------------------------------------------------------------------ + * rflputc - Write one character to a remote file + *------------------------------------------------------------------------ + */ +devcall rflputc( + struct dentry *devptr, /* Entry in device switch table */ + char ch /* Character to write */ + ) +{ + struct rflcblk *rfptr; /* Pointer to rfl control block */ + + rfptr = &rfltab[devptr->dvminor]; + + if (rflwrite(devptr, &ch, 1) != 1) { + return SYSERR; + } + + return OK; +} diff --git a/device/x86-galileo/rfs/rflread.c b/device/x86-galileo/rfs/rflread.c new file mode 100644 index 0000000..5d8979b --- /dev/null +++ b/device/x86-galileo/rfs/rflread.c @@ -0,0 +1,100 @@ +/* rflread.c - rflread */ + +#include + +/*------------------------------------------------------------------------ + * rflread - Read data from a remote file + *------------------------------------------------------------------------ + */ +devcall rflread ( + struct dentry *devptr, /* Entry in device switch table */ + char *buff, /* Buffer of bytes */ + int32 count /* Count of bytes to read */ + ) +{ + struct rflcblk *rfptr; /* Pointer to control block */ + int32 retval; /* Return value */ + struct rf_msg_rreq msg; /* Request message to send */ + struct rf_msg_rres resp; /* Buffer for response */ + int32 i; /* Counts bytes copied */ + char *from, *to; /* Used during name copy */ + int32 len; /* Length of name */ + + /* Wait for exclusive access */ + + wait(Rf_data.rf_mutex); + + /* Verify count is legitimate */ + + if ( (count <= 0) || (count > RF_DATALEN) ) { + signal(Rf_data.rf_mutex); + return SYSERR; + } + + /* Verify pseudo-device is in use */ + + rfptr = &rfltab[devptr->dvminor]; + + /* If device not currently in use, report an error */ + + if (rfptr->rfstate == RF_FREE) { + signal(Rf_data.rf_mutex); + return SYSERR; + } + + /* Verify pseudo-device allows reading */ + + if ((rfptr->rfmode & RF_MODE_R) == 0) { + signal(Rf_data.rf_mutex); + return SYSERR; + } + + /* Form read request */ + + msg.rf_type = htons(RF_MSG_RREQ); + msg.rf_status = htons(0); + msg.rf_seq = 0; /* Rfscomm will set sequence */ + from = rfptr->rfname; + to = msg.rf_name; + memset(to, NULLCH, RF_NAMLEN); /* Start name as all zero bytes */ + len = 0; + while ( (*to++ = *from++) ) { /* Copy name to request */ + if (++len >= RF_NAMLEN) { + signal(Rf_data.rf_mutex); + return SYSERR; + } + } + msg.rf_pos = htonl(rfptr->rfpos);/* Set file position */ + msg.rf_len = htonl(count); /* Set count of bytes to read */ + + /* Send message and receive response */ + + retval = rfscomm((struct rf_msg_hdr *)&msg, + sizeof(struct rf_msg_rreq), + (struct rf_msg_hdr *)&resp, + sizeof(struct rf_msg_rres) ); + + /* Check response */ + + if (retval == SYSERR) { + signal(Rf_data.rf_mutex); + return SYSERR; + } else if (retval == TIMEOUT) { + kprintf("Timeout during remote file read\n"); + signal(Rf_data.rf_mutex); + return SYSERR; + } else if (ntohs(resp.rf_status) != 0) { + signal(Rf_data.rf_mutex); + return SYSERR; + } + + /* Copy data to application buffer and update file position */ + + for (i=0; irfpos += ntohl(resp.rf_len); + + signal(Rf_data.rf_mutex); + return ntohl(resp.rf_len); +} diff --git a/device/x86-galileo/rfs/rflseek.c b/device/x86-galileo/rfs/rflseek.c new file mode 100644 index 0000000..4a84788 --- /dev/null +++ b/device/x86-galileo/rfs/rflseek.c @@ -0,0 +1,33 @@ +/* rflseek.c - rflseek */ + +#include + +/*------------------------------------------------------------------------ + * rflseek - Change the current position in an open file + *------------------------------------------------------------------------ + */ +devcall rflseek ( + struct dentry *devptr, /* Entry in device switch table */ + uint32 pos /* New file position */ + ) +{ + struct rflcblk *rfptr; /* Pointer to control block */ + + /* Wait for exclusive access */ + + wait(Rf_data.rf_mutex); + + /* Verify remote file device is open */ + + rfptr = &rfltab[devptr->dvminor]; + if (rfptr->rfstate == RF_FREE) { + signal(Rf_data.rf_mutex); + return SYSERR; + } + + /* Set the new position */ + + rfptr->rfpos = pos; + signal(Rf_data.rf_mutex); + return OK; +} diff --git a/device/x86-galileo/rfs/rflwrite.c b/device/x86-galileo/rfs/rflwrite.c new file mode 100644 index 0000000..ec3c2b9 --- /dev/null +++ b/device/x86-galileo/rfs/rflwrite.c @@ -0,0 +1,97 @@ +/* rflwrite.c - rflwrite */ + +#include + +/*------------------------------------------------------------------------ + * rflwrite - Write data to a remote file + *------------------------------------------------------------------------ + */ +devcall rflwrite ( + struct dentry *devptr, /* Entry in device switch table */ + char *buff, /* Buffer of bytes */ + int32 count /* Count of bytes to write */ + ) +{ + struct rflcblk *rfptr; /* Pointer to control block */ + int32 retval; /* Return value */ + struct rf_msg_wreq msg; /* Request message to send */ + struct rf_msg_wres resp; /* Buffer for response */ + char *from, *to; /* Used to copy name */ + int i; /* Counts bytes copied into req */ + int32 len; /* Length of name */ + + /* Wait for exclusive access */ + + wait(Rf_data.rf_mutex); + + /* Verify count is legitimate */ + + if ( (count <= 0) || (count > RF_DATALEN) ) { + signal(Rf_data.rf_mutex); + return SYSERR; + } + + /* Verify pseudo-device is in use and mode allows writing */ + + rfptr = &rfltab[devptr->dvminor]; + if ( (rfptr->rfstate == RF_FREE) || + ! (rfptr->rfmode & RF_MODE_W) ) { + signal(Rf_data.rf_mutex); + return SYSERR; + } + + /* Form write request */ + + msg.rf_type = htons(RF_MSG_WREQ); + msg.rf_status = htons(0); + msg.rf_seq = 0; /* Rfscomm will set sequence */ + from = rfptr->rfname; + to = msg.rf_name; + memset(to, NULLCH, RF_NAMLEN); /* Start name as all zero bytes */ + len = 0; + while ( (*to++ = *from++) ) { /* Copy name to request */ + if (++len >= RF_NAMLEN) { + signal(Rf_data.rf_mutex); + return SYSERR; + } + } + while ( (*to++ = *from++) ) { /* Copy name into request */ + ; + } + msg.rf_pos = htonl(rfptr->rfpos);/* Set file position */ + msg.rf_len = htonl(count); /* Set count of bytes to write */ + for (i=0; irfpos += ntohl(resp.rf_len); + + signal(Rf_data.rf_mutex); + return ntohl(resp.rf_len); +} diff --git a/device/x86-galileo/rfs/rfscomm.c b/device/x86-galileo/rfs/rfscomm.c new file mode 100644 index 0000000..bd48aac --- /dev/null +++ b/device/x86-galileo/rfs/rfscomm.c @@ -0,0 +1,85 @@ +/* rfscomm.c - rfscomm */ + +#include + +/*------------------------------------------------------------------------ + * rfscomm - Handle communication with RFS server (send request and + * receive a reply, including sequencing and retries) + *------------------------------------------------------------------------ + */ +int32 rfscomm ( + struct rf_msg_hdr *msg, /* Message to send */ + int32 mlen, /* Message length */ + struct rf_msg_hdr *reply, /* Buffer for reply */ + int32 rlen /* Size of reply buffer */ + ) +{ + int32 i; /* Counts retries */ + int32 retval; /* Return value */ + int32 seq; /* Sequence for this exchange */ + int16 rtype; /* Reply type in host byte order*/ + int32 slot; /* UDP slot */ + + /* For the first time after reboot, register the server port */ + + if ( ! Rf_data.rf_registered ) { + if ( (retval = udp_register(Rf_data.rf_ser_ip, + Rf_data.rf_ser_port, + Rf_data.rf_loc_port)) == SYSERR) { + return SYSERR; + } + Rf_data.rf_udp_slot = retval; + Rf_data.rf_registered = TRUE; + } + + /* Assign message next sequence number */ + + seq = Rf_data.rf_seq++; + msg->rf_seq = htonl(seq); + + /* Repeat RF_RETRIES times: send message and receive reply */ + + for (i=0; irf_seq) != seq) { + continue; + } + + /* Verify the type in the reply matches the request */ + + rtype = ntohs(reply->rf_type); + if (rtype != ( ntohs(msg->rf_type) | RF_MSG_RESPONSE) ) { + continue; + } + + return retval; /* Return length to caller */ + } + + /* Retries exhausted without success */ + + kprintf("Timeout on exchange with remote file server\n"); + return TIMEOUT; +} diff --git a/device/x86-galileo/rfs/rfscontrol.c b/device/x86-galileo/rfs/rfscontrol.c new file mode 100644 index 0000000..052c5ea --- /dev/null +++ b/device/x86-galileo/rfs/rfscontrol.c @@ -0,0 +1,114 @@ +/* rfscontrol.c - rfscontrol */ + +#include + +/*------------------------------------------------------------------------ + * rfscontrol - Provide control functions for the remote file system + *------------------------------------------------------------------------ + */ +devcall rfscontrol ( + struct dentry *devptr, /* Entry in device switch table */ + int32 func, /* A control function */ + int32 arg1, /* Argument #1 */ + int32 arg2 /* Argument #2 */ + ) +{ + int32 len; /* Length of name */ + struct rf_msg_sreq msg; /* Buffer for size request */ + struct rf_msg_sres resp; /* Buffer for size response */ + struct rflcblk *rfptr; /* Pointer to entry in rfltab */ + char *to, *from; /* Used during name copy */ + int32 retval; /* Return value */ + + /* Wait for exclusive access */ + + wait(Rf_data.rf_mutex); + + /* Check length and copy (needed for size) */ + + rfptr = &rfltab[devptr->dvminor]; + from = rfptr->rfname; + to = msg.rf_name; + len = 0; + memset(to, NULLCH, RF_NAMLEN); /* Start name as all zeroes */ + while ( (*to++ = *from++) ) { /* Copy name to message */ + len++; + if (len >= (RF_NAMLEN - 1) ) { + signal(Rf_data.rf_mutex); + return SYSERR; + } + } + + switch (func) { + + /* Delete a file */ + + case RFS_CTL_DEL: + if (rfsndmsg(RF_MSG_DREQ, (char *)arg1) == SYSERR) { + signal(Rf_data.rf_mutex); + return SYSERR; + } + break; + + /* Truncate a file */ + + case RFS_CTL_TRUNC: + if (rfsndmsg(RF_MSG_TREQ, (char *)arg1) == SYSERR) { + signal(Rf_data.rf_mutex); + return SYSERR; + } + break; + + + + /* Make a directory */ + + case RFS_CTL_MKDIR: + if (rfsndmsg(RF_MSG_MREQ, (char *)arg1) == SYSERR) { + signal(Rf_data.rf_mutex); + return SYSERR; + } + break; + + /* Remove a directory */ + + case RFS_CTL_RMDIR: + if (rfsndmsg(RF_MSG_XREQ, (char *)arg1) == SYSERR) { + signal(Rf_data.rf_mutex); + return SYSERR; + } + break; + + /* Obtain current file size (non-standard message size) */ + + case RFS_CTL_SIZE: + + /* Hand-craft a size request message */ + + msg.rf_type = htons(RF_MSG_SREQ); + msg.rf_status = htons(0); + msg.rf_seq = 0; /* Rfscomm will set the seq num */ + + /* Send the request to server and obtain a response */ + + retval = rfscomm( (struct rf_msg_hdr *)&msg, + sizeof(struct rf_msg_sreq), + (struct rf_msg_hdr *)&resp, + sizeof(struct rf_msg_sres) ); + if ( (retval == SYSERR) || (retval == TIMEOUT) ) { + signal(Rf_data.rf_mutex); + return SYSERR; + } else { + signal(Rf_data.rf_mutex); + return ntohl(resp.rf_size); + } + + default: + kprintf("rfscontrol: function %d not valid\n", func); + signal(Rf_data.rf_mutex); + return SYSERR; + } + + signal(Rf_data.rf_mutex); + return OK; +} diff --git a/device/x86-galileo/rfs/rfsgetmode.c b/device/x86-galileo/rfs/rfsgetmode.c new file mode 100644 index 0000000..e3e82ed --- /dev/null +++ b/device/x86-galileo/rfs/rfsgetmode.c @@ -0,0 +1,63 @@ +/* rfsgetmode.c - rfsgetmode */ + +#include + +/*------------------------------------------------------------------------ + * rfsgetmode - Parse mode argument and generate integer of mode bits + *------------------------------------------------------------------------ + */ + +int32 rfsgetmode ( + char *mode /* String of mode characters */ + ) +{ + int32 mbits; /* Mode bits to return (in host */ + /* byte order) */ + char ch; /* Next character in mode string*/ + + mbits = 0; + + /* Mode string specifies: */ + /* r - read */ + /* w - write */ + /* o - old (file must exist) */ + /* n - new (create a new file) */ + + while ( (ch = *mode++) != NULLCH) { + switch (ch) { + + case 'r': if (mbits&RF_MODE_R) { + return SYSERR; + } + mbits |= RF_MODE_R; + continue; + + case 'w': if (mbits&RF_MODE_W) { + return SYSERR; + } + mbits |= RF_MODE_W; + continue; + + case 'o': if (mbits&RF_MODE_O || mbits&RF_MODE_N) { + return SYSERR; + } + mbits |= RF_MODE_O; + break; + + case 'n': if (mbits&RF_MODE_O || mbits&RF_MODE_N) { + return SYSERR; + } + mbits |= RF_MODE_N; + break; + + default: return SYSERR; + } + } + + /* If neither read nor write specified, allow both */ + + if ( (mbits&RF_MODE_RW) == 0 ) { + mbits |= RF_MODE_RW; + } + return mbits; +} diff --git a/device/x86-galileo/rfs/rfsinit.c b/device/x86-galileo/rfs/rfsinit.c new file mode 100644 index 0000000..9eff0ad --- /dev/null +++ b/device/x86-galileo/rfs/rfsinit.c @@ -0,0 +1,39 @@ +/* rfsinit.c - rfsinit */ + +#include + +struct rfdata Rf_data; + +/*------------------------------------------------------------------------ + * rfsinit - Initialize the remote file system master device + *------------------------------------------------------------------------ + */ +devcall rfsinit( + struct dentry *devptr /* Entry in device switch table */ + ) +{ + + /* Choose an initial message sequence number */ + + Rf_data.rf_seq = 1; + + /* Set the server IP address, server port, and local port */ + + if ( dot2ip(RF_SERVER_IP, &Rf_data.rf_ser_ip) == SYSERR ) { + panic("invalid IP address for remote file server"); + } + Rf_data.rf_ser_port = RF_SERVER_PORT; + Rf_data.rf_loc_port = RF_LOC_PORT; + + /* Create a mutual exclusion semaphore */ + + if ( (Rf_data.rf_mutex = semcreate(1)) == SYSERR ) { + panic("Cannot create remote file system semaphore"); + } + + /* Specify that the server port is not yet registered */ + + Rf_data.rf_registered = FALSE; + + return OK; +} diff --git a/device/x86-galileo/rfs/rfsndmsg.c b/device/x86-galileo/rfs/rfsndmsg.c new file mode 100644 index 0000000..75917ae --- /dev/null +++ b/device/x86-galileo/rfs/rfsndmsg.c @@ -0,0 +1,46 @@ +/* rfsndmsg.c - rfsndmsg */ + +#include + +/*------------------------------------------------------------------------ + * rfsndmsg - Create and send a message that only has header fields + *------------------------------------------------------------------------ + */ +status rfsndmsg ( + uint16 type, /* Message type */ + char *name /* Null-terminated file name */ + ) +{ + struct rf_msg_hdr req; /* Request message to send */ + struct rf_msg_hdr resp; /* Buffer for response */ + int32 retval; /* Return value */ + char *to; /* Used during name copy */ + + /* Form a request */ + + req.rf_type = htons(type); + req.rf_status = htons(0); + req.rf_seq = 0; /* Rfscomm will set sequence */ + to = req.rf_name; + while ( (*to++ = *name++) ) { /* Copy name to request */ + ; + } + + /* Send message and receive response */ + + retval = rfscomm(&req, sizeof(struct rf_msg_hdr), + &resp, sizeof(struct rf_msg_hdr) ); + + /* Check response */ + + if (retval == SYSERR) { + return SYSERR; + } else if (retval == TIMEOUT) { + kprintf("Timeout during remote file server access\n"); + return SYSERR; + } else if (ntohl(resp.rf_status) != 0) { + return SYSERR; + } + + return OK; +} diff --git a/device/x86-galileo/rfs/rfsopen.c b/device/x86-galileo/rfs/rfsopen.c new file mode 100644 index 0000000..bee91a0 --- /dev/null +++ b/device/x86-galileo/rfs/rfsopen.c @@ -0,0 +1,114 @@ +/* rfsopen.c - rfsopen */ + +#include + +/*------------------------------------------------------------------------ + * rfsopen - Allocate a remote file pseudo-device for a specific file + *------------------------------------------------------------------------ + */ + +devcall rfsopen ( + struct dentry *devptr, /* Entry in device switch table */ + char *name, /* File name to use */ + char *mode /* Mode chars: 'r' 'w' 'o' 'n' */ + ) +{ + struct rflcblk *rfptr; /* Ptr to control block entry */ + struct rf_msg_oreq msg; /* Message to be sent */ + struct rf_msg_ores resp; /* Buffer to hold response */ + int32 retval; /* Return value from rfscomm */ + int32 len; /* Counts chars in name */ + char *nptr; /* Pointer into name string */ + char *fptr; /* Pointer into file name */ + int32 i; /* General loop index */ + + /* Wait for exclusive access */ + + wait(Rf_data.rf_mutex); + + /* Search control block array to find a free entry */ + + for(i=0; irfstate == RF_FREE) { + break; + } + } + if (i >= Nrfl) { /* No free table slots remain */ + signal(Rf_data.rf_mutex); + return SYSERR; + } + + /* Copy name into free table slot */ + + nptr = name; + fptr = rfptr->rfname; + len = 0; + while ( (*fptr++ = *nptr++) != NULLCH) { + len++; + if (len >= RF_NAMLEN) { /* File name is too long */ + signal(Rf_data.rf_mutex); + return SYSERR; + } + } + + /* Verify that name is non-null */ + + if (len==0) { + signal(Rf_data.rf_mutex); + return SYSERR; + } + + /* Parse mode string */ + + if ( (rfptr->rfmode = rfsgetmode(mode)) == SYSERR ) { + signal(Rf_data.rf_mutex); + return SYSERR; + } + + /* Form an open request to create a new file or open an old one */ + + msg.rf_type = htons(RF_MSG_OREQ);/* Request a file open */ + msg.rf_status = htons(0); + msg.rf_seq = 0; /* Rfscomm fills in seq. number */ + nptr = msg.rf_name; + memset(nptr, NULLCH, RF_NAMLEN);/* Initialize name to zero bytes*/ + while ( (*nptr++ = *name++) != NULLCH ) { /* Copy name to req. */ + ; + } + msg.rf_mode = htonl(rfptr->rfmode); /* Set mode in request */ + + /* Send message and receive response */ + + retval = rfscomm((struct rf_msg_hdr *)&msg, + sizeof(struct rf_msg_oreq), + (struct rf_msg_hdr *)&resp, + sizeof(struct rf_msg_ores) ); + + /* Check response */ + + if (retval == SYSERR) { + signal(Rf_data.rf_mutex); + return SYSERR; + } else if (retval == TIMEOUT) { + kprintf("Timeout during remote file open\n\r"); + signal(Rf_data.rf_mutex); + return SYSERR; + } else if (ntohs(resp.rf_status) != 0) { + signal(Rf_data.rf_mutex); + return SYSERR; + } + + /* Set initial file position */ + + rfptr->rfpos = 0; + + /* Mark state as currently used */ + + rfptr->rfstate = RF_USED; + + /* Return device descriptor of newly created pseudo-device */ + + signal(Rf_data.rf_mutex); + return rfptr->rfdev; +} diff --git a/device/x86-galileo/sdmc/sdmcclose.c b/device/x86-galileo/sdmc/sdmcclose.c new file mode 100644 index 0000000..80a0bb6 --- /dev/null +++ b/device/x86-galileo/sdmc/sdmcclose.c @@ -0,0 +1,15 @@ +/* sdmcclose.c - sdmcclose */ + +#include +#include + +/*------------------------------------------------------------------------ + * sdmcclose - Close a SD memory card device + *------------------------------------------------------------------------ + */ +devcall sdmcclose ( + struct dentry *devptr /* entry in device switch table */ + ) +{ + return OK; +} diff --git a/device/x86-galileo/sdmc/sdmccmd.c b/device/x86-galileo/sdmc/sdmccmd.c new file mode 100644 index 0000000..2c3d34a --- /dev/null +++ b/device/x86-galileo/sdmc/sdmccmd.c @@ -0,0 +1,288 @@ +/* sdmccmd.c - sdmc_cmd_err_rcvy, sdmc_issue_cmd_async, */ +/* sdmc_finalize_cmd_async, sdmc_issue_cmd_sync */ + +#include +#include + +devcall sdmc_cmd_err_rcvy ( + volatile struct sdmc_csreg *csrptr, /* SD controlelr CSR */ + uint16* error_sts /* command error status */ + ) +{ + uint16 cmd12_err_sts = 0; /* CMD12 error status */ + + kprintf("[SDMC] Error recovery %04X\n", csrptr->err_int_status); + + /* Set software reset bit for error type */ + + /* Command Error - Command software reset */ + if(csrptr->err_int_status & + (SDMC_ERR_INT_CMD_TIMEOUT_ERR | + SDMC_ERR_INT_CMD_CRC_ERR | + SDMC_ERR_INT_CMD_END_BIT_ERR | + SDMC_ERR_INT_CMD_INDEX_ERR)) { + + csrptr->sw_rst |= SDMC_SW_RST_CMD_LN; + while(csrptr->sw_rst & SDMC_SW_RST_CMD_LN) { + DELAY(SDMC_CMD_DELAY); + } + } + + /* Data error - Data software reset */ + if(csrptr->err_int_status & + (SDMC_ERR_INT_DATA_TIMEOUT_ERR | + SDMC_ERR_INT_DATA_CRC_ERR | + SDMC_ERR_INT_DATA_END_BIT_ERR)) { + + csrptr->sw_rst |= SDMC_SW_RST_DAT_LN; + while(csrptr->sw_rst & SDMC_SW_RST_DAT_LN) { + DELAY(SDMC_CMD_DELAY); + } + } + + kprintf("After software reset\n"); + + /* Save and clear the error status */ + (*error_sts) = csrptr->err_int_status; + csrptr->err_int_status |= (*error_sts); + + /* Issue the abort command (CMD12) */ + /* Do not perform error recovery */ + sdmc_issue_cmd_sync(csrptr, SDMC_ABT, 0x00000000, &cmd12_err_sts, + SDMC_CMD_NO_ERR_RCVY); + + /* Wait for command and DAT inhibit signals to be cleared */ + while(csrptr->pre_state & SDMC_PRE_STATE_CMD_INHIBIT_CMD) { + DELAY(SDMC_CMD_DELAY); + } + while(csrptr->pre_state & SDMC_PRE_STATE_CMD_INHIBIT_DAT) { + DELAY(SDMC_CMD_DELAY); + } + + /* Clear the command complete interrupt */ + if(csrptr->nml_int_status & SDMC_NML_INT_CMD_COMP) { + csrptr->nml_int_status |= SDMC_NML_INT_CMD_COMP; + } + + /* Check status of abort command */ + if(csrptr->err_int_status & + (SDMC_ERR_INT_CMD_TIMEOUT_ERR | + SDMC_ERR_INT_CMD_CRC_ERR | + SDMC_ERR_INT_CMD_END_BIT_ERR | + SDMC_ERR_INT_CMD_INDEX_ERR)) { + + /* Clear the error status */ + csrptr->err_int_status |= csrptr->err_int_status; + + /* Error in abort, error is non recoverable */ + return SDMC_RC_NON_RECOVERABLE_ERROR; + } + + /* Check for data timeout */ + if(csrptr->err_int_status & SDMC_ERR_INT_DATA_TIMEOUT_ERR) { + + /* Clear the error status */ + csrptr->err_int_status |= csrptr->err_int_status; + + /* Data timeout in abort, error is non recoverable */ + return SDMC_RC_NON_RECOVERABLE_ERROR; + } + + /* Check data line signal level */ + DELAY(1); /* Must wait at least 40 microseconds */ + if(csrptr->pre_state & SDMC_PRE_STATE_DATA_LN_SIG_LVL) { + return SDMC_RC_RECOVERABLE_ERR; + } + return SDMC_RC_NON_RECOVERABLE_ERROR; +} + +devcall sdmc_issue_cmd_async ( + volatile struct sdmc_csreg *csrptr, /* SD controller CSR */ + uint16 cmd_value, /* SDMC Command to issue*/ + uint32 arg_value /* Command argument */ + ) +{ + /* Wait for command inhibit bits to be cleared */ + + kprintf("State Prior to CMD: %08X %08X %08X %08X %08X %04X %04X\n", + csrptr->pre_state, csrptr->response0, csrptr->response2, + csrptr->response4, csrptr->response6, + csrptr->nml_int_status, csrptr->err_int_status); + + while(csrptr->pre_state & SDMC_PRE_STATE_CMD_INHIBIT_CMD) { + DELAY(SDMC_CMD_DELAY); + } + while(csrptr->pre_state & SDMC_PRE_STATE_CMD_INHIBIT_DAT) { + DELAY(SDMC_CMD_DELAY); + } + + kprintf("Issuing command %04X %08X\n", cmd_value, arg_value); + + /* Ensure that the command complete interrupt status are enabled*/ + csrptr->nrm_int_status_en |= SDMC_CMD_COMP_STAT_EN | + SDMC_TX_COMP_STAT_EN | SDMC_CRD_INT_STAT_EN; + csrptr->err_int_stat_en |= SDMC_ERR_INT_CMD_TIMEOUT_ERR_STAT_EN | + SDMC_ERR_INT_CMD_CRC_ERR_STAT_EN | + SDMC_ERR_INT_CMD_END_BIT_ERR_STAT_EN | + SDMC_ERR_INT_CMD_IND_ERR_STAT_EN; + + /* Asynchronous command execution, ensure that interrupt */ + /* signals are enabled */ + csrptr->nrm_int_sig_en |= SDMC_CMD_COMP_SIG_EN | + SDMC_TX_COMP_SIG_EN | SDMC_CRD_INT_SIG_EN; + csrptr->err_int_sig_en |= SDMC_ERR_INT_CMD_TIMEOUT_ERR_SIG_EN | + SDMC_ERR_INT_CMD_CRC_ERR_SIG_EN | + SDMC_ERR_INT_CMD_END_BIT_ERR_SIG_EN | + SDMC_ERR_INT_CMD_IND_ERR_SIG_EN; + + /* Issue the command */ + csrptr->argument = arg_value; + csrptr->cmd = cmd_value; + + return SDMC_RC_OK; +} + +devcall sdmc_finalize_cmd_async ( + volatile struct sdmc_csreg *csrptr, /* SD controller CSR */ + uint16* error_sts /* Error status */ + ) +{ + kprintf("CMD INT: %04X %04X\n", csrptr->nml_int_status, + csrptr->err_int_status); + + /* Clear the command complete interrupt */ + if(csrptr->nml_int_status & SDMC_NML_INT_CMD_COMP) { + csrptr->nml_int_status |= SDMC_NML_INT_CMD_COMP; + } + + /* Clear the error interrupt and perform error recovery */ + if(csrptr->nml_int_status & SDMC_NML_INT_ERR_INT) { + csrptr->nml_int_status |= SDMC_NML_INT_ERR_INT; + return sdmc_cmd_err_rcvy(csrptr, error_sts); + } + + kprintf("State After CMD: %08X %08X %08X %08X %08X %04X %04X\n", + csrptr->pre_state, csrptr->response0, csrptr->response2, + csrptr->response4, csrptr->response6, + csrptr->nml_int_status, csrptr->err_int_status); + + return SDMC_RC_OK; +} + +devcall sdmc_issue_cmd_sync ( + volatile struct sdmc_csreg *csrptr, /* SD controller CSR */ + uint16 cmd_value, /* SDMC Command to issue*/ + uint32 arg_value, /* Command argument */ + uint16* error_sts, /* Error status */ + uint8 flags /* Command execut. flags*/ + ) +{ + uint8 rc = SDMC_RC_OK; + + /* Save old contents of interrupt registers */ + uint16 save_nrm_int_stat_en = csrptr->nrm_int_status_en; + uint16 save_nrm_int_sig_en = csrptr->nrm_int_sig_en; + uint16 save_err_int_stat_en = csrptr->err_int_stat_en; + uint16 save_err_int_sig_en = csrptr->err_int_sig_en; + + /* Wait for command inhibit bits to be cleared */ + + kprintf("State Prior to CMD: %08X %08X %08X %08X %08X %04X %04X\n", + csrptr->pre_state, csrptr->response0, csrptr->response2, + csrptr->response4, csrptr->response6, + csrptr->nml_int_status, csrptr->err_int_status); + + while(csrptr->pre_state & SDMC_PRE_STATE_CMD_INHIBIT_CMD) { + DELAY(SDMC_CMD_DELAY); + } + while(csrptr->pre_state & SDMC_PRE_STATE_CMD_INHIBIT_DAT) { + DELAY(SDMC_CMD_DELAY); + } + + kprintf("Issuing command %04X %08X\n", cmd_value, arg_value); + + /* Ensure that the command complete interrupt status are enabled*/ + + csrptr->nrm_int_status_en |= SDMC_CMD_COMP_STAT_EN | + SDMC_TX_COMP_STAT_EN | SDMC_CRD_INT_STAT_EN; + csrptr->err_int_stat_en |= SDMC_ERR_INT_CMD_TIMEOUT_ERR_STAT_EN | + SDMC_ERR_INT_CMD_CRC_ERR_STAT_EN | + SDMC_ERR_INT_CMD_END_BIT_ERR_STAT_EN | + SDMC_ERR_INT_CMD_IND_ERR_STAT_EN; + + if(flags & SDMC_CMD_DAT_TRNS) { + csrptr->nrm_int_status_en |= SDMC_TX_COMP_STAT_EN; + csrptr->err_int_stat_en |= + SDMC_ERR_INT_DATA_TIMEOUT_ERR_STAT_EN | + SDMC_ERR_INT_DATA_CRC_ERR_STAT_EN | + SDMC_ERR_INT_DATA_END_BIT_ERR_STAT_EN; + } + + /* Synchronous command execution, ensure that interrupt */ + /* signals are not enabled */ + csrptr->nrm_int_sig_en &= ~(SDMC_CMD_COMP_SIG_EN | + SDMC_TX_COMP_SIG_EN | SDMC_CRD_INT_SIG_EN); + csrptr->err_int_sig_en &= ~( + SDMC_ERR_INT_CMD_TIMEOUT_ERR_SIG_EN | + SDMC_ERR_INT_CMD_CRC_ERR_SIG_EN | + SDMC_ERR_INT_CMD_END_BIT_ERR_SIG_EN | + SDMC_ERR_INT_CMD_IND_ERR_SIG_EN | + SDMC_ERR_INT_DATA_TIMEOUT_ERR_SIG_EN | + SDMC_ERR_INT_DATA_CRC_ERR_SIG_EN | + SDMC_ERR_INT_DATA_END_BIT_ERR_SIG_EN); + + /* Issue the command */ + csrptr->argument = arg_value; + csrptr->cmd = cmd_value; + + /* Wait for command to complete */ + while(!(csrptr->nml_int_status & SDMC_NML_INT_CMD_COMP) && + !(csrptr->nml_int_status & SDMC_NML_INT_ERR_INT)) { + DELAY(SDMC_CMD_DELAY); + } + + /* Clear the command complete interrupt */ + if(csrptr->nml_int_status & SDMC_NML_INT_CMD_COMP) { + csrptr->nml_int_status |= SDMC_NML_INT_CMD_COMP; + } + + if(flags & SDMC_CMD_DAT_TRNS) { + + /* Wait for data transmission to complete */ + while(!(csrptr->nml_int_status & SDMC_NML_INT_TX_COMP) && + !(csrptr->nml_int_status & SDMC_NML_INT_ERR_INT)) { + kprintf( + "Waiting for data trans %08X %04X %04X %08X %02X\n", + csrptr->sys_adr, csrptr->nml_int_status, + csrptr->err_int_status, csrptr->pre_state, + csrptr->blk_gap_ctl); + DELAY(SDMC_CMD_DELAY); + } + + /* Clear the data transmission complete interrupt */ + if(csrptr->nml_int_status & SDMC_NML_INT_TX_COMP) { + csrptr->nml_int_status |= SDMC_NML_INT_TX_COMP; + } + } + + /* Clear the error interrupt and perform error recovery */ + if(csrptr->nml_int_status & SDMC_NML_INT_ERR_INT) { + csrptr->nml_int_status |= SDMC_NML_INT_ERR_INT; + if(!(flags & SDMC_CMD_NO_ERR_RCVY)) { + rc = sdmc_cmd_err_rcvy(csrptr, error_sts); + } + } + + kprintf("State After CMD: %08X %08X %08X %08X %08X %04X %04X\n", + csrptr->pre_state, csrptr->response0, csrptr->response2, + csrptr->response4, csrptr->response6, + csrptr->nml_int_status, csrptr->err_int_status); + + /* Restore saved interrupt enable bits */ + csrptr->nrm_int_status_en = save_nrm_int_stat_en; + csrptr->nrm_int_sig_en = save_nrm_int_sig_en; + csrptr->err_int_stat_en = save_err_int_stat_en; + csrptr->err_int_sig_en = save_err_int_sig_en; + + return rc; +} diff --git a/device/x86-galileo/sdmc/sdmcdispatch.S b/device/x86-galileo/sdmc/sdmcdispatch.S new file mode 100644 index 0000000..d191360 --- /dev/null +++ b/device/x86-galileo/sdmc/sdmcdispatch.S @@ -0,0 +1,20 @@ +/* sdmcDispatch.S - sdmcDispatch */ + +#include + .text + .globl sdmcdispatch + .globl sdmcinterrupt +sdmcdispatch: + pushal + pushfl + cli + movb $EOI,%al # clear the interrupt + outb %al,$OCW1_2 + movb $EOI,%al + outb %al,$OCW2_2 + + call sdmcinterrupt + + popfl + popal + iret diff --git a/device/x86-galileo/sdmc/sdmcinit.c b/device/x86-galileo/sdmc/sdmcinit.c new file mode 100644 index 0000000..0ad852a --- /dev/null +++ b/device/x86-galileo/sdmc/sdmcinit.c @@ -0,0 +1,56 @@ +/* sdmcInit.c - sdmcInit */ + +#include +#include + +struct sdmcblk sdmctab[Nsdmc]; + +/*------------------------------------------------------------------------ + * sdmcinit - initialize the SD memory card device + *------------------------------------------------------------------------ + */ +devcall sdmcinit ( + struct dentry *devptr /* entry in device switch table */ + ) +{ + volatile struct sdmc_csreg *csrptr; /* address of SD controller's CSR */ + uint32 pciinfo; /* PCI info to read config */ + + /* Search for the SD memory card device on the PCI bus */ + pciinfo = find_pci_device(INTEL_QUARK_SDIO_PCI_DID, INTEL_QUARK_SDIO_PCI_VID, 0); + if((int)pciinfo == SYSERR) { + kprintf("[SDMC] Device not found\n"); + return SYSERR; + } + + /* Read PCI config space to get memory base address */ + if(pci_read_config_dword(pciinfo, 0x10, (uint32 *)&devptr->dvcsr) == SYSERR) { + kprintf("[SDMC] Unable to retrieve CSR\n"); + return SYSERR; + } + + /* Enable CSR Memory Space, Enable Bus Master */ + pci_write_config_word(pciinfo, 0x4, 0x0006); + + /* Set interrupt IRQ */ + set_evec(devptr->dvirq, (uint32)sdmcdispatch); + + /* Initialize the SD CS register */ + csrptr = (struct sdmc_csreg *)devptr->dvcsr; + + /* Enable and register for card insertion and removal interrupts */ + csrptr->nrm_int_status_en = SDMC_CRD_INS_STAT_EN | SDMC_CRD_RMV_STAT_EN | SDMC_CRD_INT_STAT_EN; + csrptr->nrm_int_sig_en = SDMC_CRD_INS_SIG_EN | SDMC_CRD_RMV_SIG_EN | SDMC_CRD_INT_SIG_EN; + csrptr->err_int_stat_en = 0; + csrptr->err_int_sig_en = 0; + + /* + csrptr->nrm_int_status_en = 0x1FF; + csrptr->nrm_int_sig_en = 0x1FF; + + csrptr->err_int_stat_en = 0x7FF; + csrptr->err_int_sig_en = 0x7FF; + */ + + return OK; +} diff --git a/device/x86-galileo/sdmc/sdmcinterrupt.c b/device/x86-galileo/sdmc/sdmcinterrupt.c new file mode 100644 index 0000000..c0b6359 --- /dev/null +++ b/device/x86-galileo/sdmc/sdmcinterrupt.c @@ -0,0 +1,72 @@ +/* sdmcinterrupt.c - sdmcinterrupt */ + +#include +#include + +/*------------------------------------------------------------------------ + * sdmcinterrupt - handle an interrupt for a SD memory card device + *------------------------------------------------------------------------ + */ +void sdmcinterrupt(void) { + struct dentry *devptr; /* address of device control blk*/ + volatile struct sdmc_csreg *csrptr; /* address of SD controller's CSR */ + struct sdmcblk *sdmcptr; /* Pointer to sdmctab entry */ + + /* Get CSR address of the device */ + + devptr = (struct dentry *) &devtab[SDMC]; + csrptr = (struct sdmc_csreg *) devptr->dvcsr; + sdmcptr = &sdmctab[devptr->dvminor]; + + kprintf("SDMC INT: %04X %04X\n", csrptr->nml_int_status, csrptr->err_int_status); + + /* Check for card insertion interrupt */ + if(csrptr->nml_int_status & SDMC_NML_INT_CRD_INS) { + + /* Clear the card insertion interrupt */ + csrptr->nml_int_status |= SDMC_NML_INT_CRD_INS; + + /* Check current card present status to see if it is actually inserted */ + if(csrptr->pre_state & SDMC_PRE_STATE_CRD_INS) { + + /* Open the device */ + sdmcopen(devptr, "", ""); + } + return; + } + + /* Check for card removal interrupt */ + if(csrptr->nml_int_status & SDMC_NML_INT_CRD_RM) { + + /* Clear the card removal interrupt */ + csrptr->nml_int_status |= SDMC_NML_INT_CRD_RM; + + /* Check current card present status to see if it is actually removed */ + if(!(csrptr->pre_state & SDMC_PRE_STATE_CRD_INS)) { + + /* Close the device */ + //sdmcClose + } + return; + } + + /* Check for command complete interrupt */ + if(csrptr->nml_int_status & SDMC_NML_INT_CMD_COMP) { + + /* Clear the command complete interrupt */ + csrptr->nml_int_status |= SDMC_NML_INT_CMD_COMP; + + /* Signal the command semaphore */ + signal(sdmcptr->cmd_sem); + } + + /* Check for transfer complete interrupt */ + if(csrptr->nml_int_status & SDMC_NML_INT_TX_COMP) { + + /* Clear the transfer complete interrupt */ + csrptr->nml_int_status |= SDMC_NML_INT_TX_COMP; + + /* Signal the transfer semaphore */ + signal(sdmcptr->tx_sem); + } +} diff --git a/device/x86-galileo/sdmc/sdmcopen.c b/device/x86-galileo/sdmc/sdmcopen.c new file mode 100644 index 0000000..8bf40d0 --- /dev/null +++ b/device/x86-galileo/sdmc/sdmcopen.c @@ -0,0 +1,204 @@ +/* sdmcopen.c - sdmcopen */ + +#include +#include + +/*------------------------------------------------------------------------ + * sdmc_set_bus_power - set SD voltage + *------------------------------------------------------------------------ + */ +devcall sdmc_set_bus_power ( + volatile struct sdmc_csreg *csrptr /* address of SD controller's CSR */ + ) +{ + uint8 sdmc_voltage_select = 0; + + /* Determine max supported voltage */ + if(csrptr->capabilities & SDMC_CAP_VOLT_SUPPORT_3P3V) { + sdmc_voltage_select = SDMC_PWR_CTL_SD_BUS_VOL_SEL_3P3V; + } else if(csrptr->capabilities & SDMC_CAP_VOLT_SUPPORT_3P0V) { + sdmc_voltage_select = SDMC_PWR_CTL_SD_BUS_VOL_SEL_3P0V; + } else if(csrptr->capabilities & SDMC_CAP_VOLT_SUPPORT_1P8V) { + sdmc_voltage_select = SDMC_PWR_CTL_SD_BUS_VOL_SEL_1P8V; + } else { + /* Unknown supported voltage */ + return SDMC_RC_NON_RECOVERABLE_ERROR; + } + + /* Set the controller voltage */ + csrptr->pwr_ctl &= SDMC_PWR_CTL_SD_BUS_VOL_SEL_CLR; + csrptr->pwr_ctl |= sdmc_voltage_select; + + /* Set bus power flag */ + csrptr->pwr_ctl |= SDMC_PWR_CTL_SD_BUS_PWR; + + return SDMC_RC_OK; +} + +/*------------------------------------------------------------------------ + * sdmc_set_clock - set SDCLK frequency + *------------------------------------------------------------------------ + */ +devcall sdmc_set_clock ( + volatile struct sdmc_csreg *csrptr /* address of SD controller's CSR */ + ) +{ + /* Change to the SD Clock is not allowed while command inhibit is set */ + while(csrptr->pre_state & SDMC_PRE_STATE_CMD_INHIBIT_CMD) { + DELAY(SDMC_CMD_DELAY); + } + while(csrptr->pre_state & SDMC_PRE_STATE_CMD_INHIBIT_DAT) { + DELAY(SDMC_CMD_DELAY); + } + + /* Disable the SD Clock */ + csrptr->clk_ctl &= ~(SDMC_CLK_CTL_SD_CLK_EN); + + /* Set the SD clock frequency divisor */ + csrptr->clk_ctl &= SDMC_CLK_CTL_SD_FREQ_HIGH_MASK; + + /* Internal enable the SD clock */ + csrptr->clk_ctl |= SDMC_CLK_CTL_INT_CLK_EN; + + /* Wait for SD clock to be stable */ + while(!(csrptr->clk_ctl & SDMC_CLK_CTL_INT_CLK_STABLE)) { + DELAY(SDMC_CMD_DELAY); + } + + /* Set SD Clock enable */ + csrptr->clk_ctl |= SDMC_CLK_CTL_SD_CLK_EN; + + return SDMC_RC_OK; +} + +/*------------------------------------------------------------------------ + * sdmc_set_dat_timeout - set timeout for data lines + *------------------------------------------------------------------------ + */ +devcall sdmc_set_dat_timeout ( + volatile struct sdmc_csreg *csrptr /* address of SD controller's CSR */ + ) +{ + kprintf("TIMEOUT %08X %02X\n", csrptr->capabilities, csrptr->timeout_ctl); + + return SDMC_RC_OK; +} + +/*------------------------------------------------------------------------ + * sdmcopen - open an SD memory card + *------------------------------------------------------------------------ + */ +devcall sdmcopen ( + struct dentry *devptr, /* entry in device switch table */ + char *name, /* name to open */ + char *mode /* mode argument */ + ) +{ + volatile struct sdmc_csreg *csrptr; /* address of SD controller's CSR */ + struct sdmcblk *sdmcptr; /* Pointer to sdmctab entry */ + uint16 error_sts = 0; /* SDMC command error status */ + uint32 cmd_arg = 0; /* Value of argument register */ + byte first_ACMD41 = 1; /* Set for the first ACMD41 */ + + /* Initialize structure pointers */ + sdmcptr = &sdmctab[devptr->dvminor]; + csrptr = (struct sdmc_csreg *) devptr->dvcsr; + + /* Initialize card identifiers */ + sdmcptr->rca = 0; + memset(sdmcptr->cid, 0x00, sizeof(sdmcptr->cid)); + + sdmcptr->cmd8 = 1; /* assume card supports CMD8 */ + sdmcptr->sdio = 0; /* assume not an SDIO card */ + + /* Set the clock speed */ + sdmc_set_clock(csrptr); + + /* Set the bus voltage */ + sdmc_set_bus_power(csrptr); + + /* Set the data line timeout value */ + sdmc_set_dat_timeout(csrptr); + + /* Issue card reset command (CMD0) */ + if(sdmc_issue_cmd_sync(csrptr, SDMC_CMD0, 0x00000000, &error_sts, SDMC_CMD_NO_FLAGS) != SDMC_RC_OK) { + kprintf("[SDMC] Error in CMD0: %04X %04X", SDMC_CMD0, error_sts); + return SYSERR; + } + + /* Issue voltage check command (CMD8) */ + if(sdmc_issue_cmd_sync(csrptr, SDMC_CMD8, 0x00000101, &error_sts, SDMC_CMD_NO_FLAGS) != SDMC_RC_OK) { + kprintf("[SDMC] Error in CMD8: %04X %04X", SDMC_CMD8, error_sts); + return SYSERR; + } + /* Error in CMD8 - card must not support it */ + if(error_sts & SDMC_ERR_INT_CMD_TIMEOUT_ERR || + csrptr->response0 != 0x00000101) { + sdmcptr->cmd8 = 0; + } + + /* Issue inquiry voltage state (ACMD41) */ + /* To send an application command (ACMD) a CMD55 must first be sent */ + /* to tell the controller to expect an application command */ + if(sdmc_issue_cmd_sync(csrptr, SDMC_CMD55, 0x00000000, &error_sts, SDMC_CMD_NO_FLAGS) != SDMC_RC_OK) { + kprintf("[SDMC] Error in CMD55: %04X %04X", SDMC_CMD55, error_sts); + return SYSERR; + } + if(sdmc_issue_cmd_sync(csrptr, SDMC_ACMD41, 0x00000000, &error_sts, SDMC_CMD_NO_FLAGS) != SDMC_RC_OK) { + kprintf("[SDMC] Error in ACMD41: %04X %04X", SDMC_ACMD41, error_sts); + return SYSERR; + } + + /* Issue initialize card command (ACMD41) */ + cmd_arg = SDMC_OCR_MASK & csrptr->response0; /* Set OCR */ + if(csrptr->response0 & SDMC_R3_S18A) { /* Set switch to 1.8V is card supports */ + cmd_arg |= SDMC_ACMD41_S18R; + } + cmd_arg |= SDMC_ACMD41_XPC | SDMC_ACMD41_HCS; /* Set high capacity support */ + /* and extended performance control */ + + /* The card initialization command (ACMD41) must be continuously sent until */ + /* unitialization has completed */ + do { + if(!first_ACMD41) { + DELAY(SDMC_CMD_DELAY); + } + + /* To send an application command (ACMD) a CMD55 must first be sent */ + /* to tell the controller to expect an application command */ + if(sdmc_issue_cmd_sync(csrptr, SDMC_CMD55, 0x00000000, &error_sts, SDMC_CMD_NO_FLAGS) != SDMC_RC_OK) { + kprintf("[SDMC] Error in CMD55: %04X %04X", SDMC_CMD55, error_sts); + return SYSERR; + } + /* Send the card initialization command */ + if(sdmc_issue_cmd_sync(csrptr, SDMC_ACMD41, cmd_arg, &error_sts, SDMC_CMD_NO_FLAGS) != SDMC_RC_OK) { + kprintf("[SDMC] Error in ACMD41: %04X %04X", SDMC_ACMD41, error_sts); + return SYSERR; + } + + first_ACMD41 = 0; + } while(!(csrptr->response0 & SDMC_R3_BUSY)); + + /* TODO run voltage switch procedure of the card supports 1.8V signaling */ + + /* Retrieve the card's card identifier (CID) */ + if(sdmc_issue_cmd_sync(csrptr, SDMC_CMD2, 0, &error_sts, SDMC_CMD_NO_FLAGS) != SDMC_RC_OK) { + kprintf("[SDMC] Error in CMD2: %04X %04X", SDMC_CMD2, error_sts); + return SYSERR; + } + memcpy(sdmcptr->cid, (char*)&csrptr->response0, 16); + + /* Retrieve the card's relative card address (RCA) */ + if(sdmc_issue_cmd_sync(csrptr, SDMC_CMD3, 0, &error_sts, SDMC_CMD_NO_FLAGS) != SDMC_RC_OK) { + kprintf("[SDMC] Error in CMD3: %04X %04X", SDMC_CMD3, error_sts); + return SYSERR; + } + sdmcptr->rca = csrptr->response0 & SDMC_R6_RCA_MASK; + + sdmcptr->cmd_sem = semcreate(0); + if((int)sdmcptr->cmd_sem == SYSERR) { + return SYSERR; + } + + return devptr->dvnum; +} diff --git a/device/x86-galileo/sdmc/sdmcread.c b/device/x86-galileo/sdmc/sdmcread.c new file mode 100644 index 0000000..39232bd --- /dev/null +++ b/device/x86-galileo/sdmc/sdmcread.c @@ -0,0 +1,211 @@ +/* sdmcRead.c - sdmcread */ + +#include +#include + +devcall sdmcread_nodma ( + struct dentry *devptr, /* entry in device switch table */ + char *buff, /* buffer to hold disk block */ + int32 blk /* block number of block to read*/ + ) +{ + volatile struct sdmc_csreg *csrptr; /* address of SD controller's CSR */ + //struct sdmcblk *sdmcptr; /* Pointer to sdmctab entry */ + uint16 error_sts = 0; /* SDMC command error status */ + uint32 cmd_arg = 0; + char* buff_ptr = buff; + uint32 i; + + //sdmcptr = &sdmctab[devptr->dvminor]; + csrptr = (struct sdmc_csreg *) devptr->dvcsr; + + /* Issue command CMD16 - set block size */ + if(sdmc_issue_cmd_sync(csrptr, SDMC_CMD16, 512, &error_sts, SDMC_CMD_NO_FLAGS) != SDMC_RC_OK) { + kprintf("[SDMC] Error in CMD16: %04X %04X", SDMC_CMD16, error_sts); + return SYSERR; + } + + csrptr->nrm_int_status_en = 0x1FF; + csrptr->err_int_stat_en = 0x7FF; + + csrptr->blk_size = 0x00000200; + csrptr->blk_count = 1; + cmd_arg = blk; + + /* Set transmit mode */ + /* Single block read no DMA */ + csrptr->tx_mode = 0x0016; + + if(sdmc_issue_cmd_sync(csrptr, SDMC_CMD17, cmd_arg, &error_sts, SDMC_CMD_NO_FLAGS) != SDMC_RC_OK) { + kprintf("[SDMC] Error in CMD17: %04X %04X\n", SDMC_CMD17, error_sts); + return SYSERR; + } + + kprintf("INTSTS %08X %08X\n", csrptr->nrm_int_status_en, csrptr->err_int_stat_en); + + /* + if(sdmc_issue_cmd_sync(csrptr, SDMC_CMD12, 0x00000000, &error_sts, SDMC_CMD_NO_FLAGS) != SDMC_RC_OK) { + kprintf("[SDMC] Error in CMD12: %04X %04X\n", SDMC_CMD17, error_sts); + return SYSERR; + } + */ + + for(i = 0; i < 512/sizeof(csrptr->buf_data_port); i++) { + while(!(csrptr->nml_int_status & SDMC_NML_INT_BUF_RD_RDY)) { + //kprintf("INT %08X %04X %04X %08X\n", csrptr->pre_state, csrptr->nml_int_status, csrptr->err_int_status, csrptr->buf_data_port); + DELAY(SDMC_CMD_DELAY); + } + csrptr->nml_int_status |= SDMC_NML_INT_BUF_RD_RDY; + + memcpy(buff_ptr, (char*)&csrptr->buf_data_port, sizeof(csrptr->buf_data_port)); + buff_ptr += sizeof(csrptr->buf_data_port); + + kprintf("Read block: %d\n", i); + } + + return OK; +} + + +devcall sdmcread_dma ( + struct dentry *devptr, /* entry in device switch table */ + char *buff, /* buffer to hold disk block */ + int32 blk /* block number of block to read*/ + ) +{ + volatile struct sdmc_csreg *csrptr; /* address of SD controller's CSR */ + struct sdmcblk *sdmcptr; /* Pointer to sdmctab entry */ + uint16 error_sts = 0; /* SDMC command error status */ + uint32 cmd_arg = 0; + char* buff_ptr = buff; + uint32 i; + + sdmcptr = &sdmctab[devptr->dvminor]; + csrptr = (struct sdmc_csreg *) devptr->dvcsr; + + /* Issue command CMD16 - set block size */ + if(sdmc_issue_cmd_sync(csrptr, SDMC_CMD16, 512, &error_sts, SDMC_CMD_NO_FLAGS) != SDMC_RC_OK) { + kprintf("[SDMC] Error in CMD16: %04X %04X", SDMC_CMD16, error_sts); + return SYSERR; + } + + csrptr->nrm_int_status_en = 0x1FF; + csrptr->err_int_stat_en = 0x7FF; + csrptr->err_int_stat_en &= ~(SDMC_ERR_INT_DATA_TIMEOUT_ERR); + + csrptr->sys_adr = (uint32)buff; + csrptr->blk_size = 0x00000200; + csrptr->blk_count = 1; + cmd_arg = blk; + + /* Set transmit mode */ + /* Single block read DMA */ + csrptr->tx_mode = 0x0011; + + if(sdmc_issue_cmd_sync(csrptr, SDMC_CMD17, cmd_arg, &error_sts, SDMC_CMD_DAT_TRNS) != SDMC_RC_OK) { + kprintf("[SDMC] Error in CMD17: %04X %04X\n", SDMC_CMD17, error_sts); + //return SYSERR; + } + + kprintf("INTSTS %08X %08X\n", csrptr->nrm_int_status_en, csrptr->err_int_stat_en); + + cmd_arg = sdmcptr->rca; + if(sdmc_issue_cmd_sync(csrptr, SDMC_CMD13, cmd_arg, &error_sts, SDMC_CMD_NO_FLAGS) != SDMC_RC_OK) { + kprintf("[SDMC] Error in CMD13: %04X %04X\n", SDMC_CMD13, error_sts); + return SYSERR; + } + + return SYSERR; + + /* + if(sdmc_issue_cmd_sync(csrptr, SDMC_CMD12, 0x00000000, &error_sts, SDMC_CMD_NO_FLAGS) != SDMC_RC_OK) { + kprintf("[SDMC] Error in CMD12: %04X %04X\n", SDMC_CMD17, error_sts); + return SYSERR; + } + */ + + for(i = 0; i < 512/sizeof(csrptr->buf_data_port); i++) { + while(!(csrptr->nml_int_status & SDMC_NML_INT_BUF_RD_RDY)) { + //kprintf("INT %08X %04X %04X %08X\n", csrptr->pre_state, csrptr->nml_int_status, csrptr->err_int_status, csrptr->buf_data_port); + DELAY(SDMC_CMD_DELAY); + } + csrptr->nml_int_status |= SDMC_NML_INT_BUF_RD_RDY; + + memcpy(buff_ptr, (char*)&csrptr->buf_data_port, sizeof(csrptr->buf_data_port)); + buff_ptr += sizeof(csrptr->buf_data_port); + + kprintf("Read block: %d\n", i); + } + + return OK; +} + + +/*------------------------------------------------------------------------ + * sdmcread - Read data from an SD memory card + *------------------------------------------------------------------------ + */ +devcall sdmcread ( + struct dentry *devptr, /* entry in device switch table */ + char *buff, /* buffer to hold disk block */ + int32 blk /* block number of block to read*/ + ) +{ + volatile struct sdmc_csreg *csrptr; /* address of SD controller's CSR */ + struct sdmcblk *sdmcptr; /* Pointer to sdmctab entry */ + uint16 error_sts = 0; /* SDMC command error status */ + uint32 cmd_arg = 0; + + /* Initialize structure pointers */ + sdmcptr = &sdmctab[devptr->dvminor]; + csrptr = (struct sdmc_csreg *) devptr->dvcsr; + + /* Retrieve the current card status to ensure it is ready for I/O */ + cmd_arg = sdmcptr->rca; + if(sdmc_issue_cmd_sync(csrptr, SDMC_CMD13, cmd_arg, &error_sts, SDMC_CMD_NO_FLAGS) != SDMC_RC_OK) { + kprintf("[SDMC] Error in CMD13: %04X %04X", SDMC_CMD13, error_sts); + return SYSERR; + } + + switch(csrptr->response0 & SDMC_R1_CURRENT_STATE) { + + /* Card is in initial state the device */ + /* must be reopened to allow I/O */ + case SDMC_R1_IDLE_STATE: + case SDMC_R1_READY_STATE: + case SDMC_R1_IDENT_STATE: + /* TODO close and reopen the device */ + return SYSERR; + break; + + /* Standby state, issue CMD7 to select the card */ + case SMDC_R1_STBY_STATE: + cmd_arg = sdmcptr->rca; + if(sdmc_issue_cmd_sync(csrptr, SDMC_CMD7, cmd_arg, &error_sts, SDMC_CMD_NO_FLAGS) != SDMC_RC_OK) { + kprintf("[SDMC] Error in CMD7: %04X %04X", SDMC_CMD7, error_sts); + return SYSERR; + } + break; + + /* Card is already in data transfer state */ + case SDMC_R1_TRAN_STATE: + case SDMC_R1_DATA_STATE: + case SDMC_R1_RCV_STATE: + break; + + /* Card is in some other state */ + /* must be reopened to allow I/O */ + case SDMC_R1_PRG_STATE: + case SMDC_R1_DIS_STATE: + /* TODO close and reopen the device */ + return SYSERR; + break; + + default: + return SYSERR; + } + + sdmcread_dma(devptr, buff, blk); + + return OK; +} diff --git a/device/x86-galileo/sdmc/sdmcwrite.c b/device/x86-galileo/sdmc/sdmcwrite.c new file mode 100644 index 0000000..ccaed87 --- /dev/null +++ b/device/x86-galileo/sdmc/sdmcwrite.c @@ -0,0 +1,19 @@ +/* sdmcwrite.c - sdmcwrite */ + +#include +#include + +/*------------------------------------------------------------------------ + * sdmcwrite - Write a buffer to an SD memory card + *------------------------------------------------------------------------ + */ +devcall sdmcwrite ( + struct dentry *devptr, /* entry in device switch table */ + char *buff, /* buffer to hold disk block */ + int32 blk /* block number of disk block */ + ) +{ + + + return OK; +} diff --git a/device/x86-galileo/tty/ttycontrol.c b/device/x86-galileo/tty/ttycontrol.c new file mode 100644 index 0000000..96b12da --- /dev/null +++ b/device/x86-galileo/tty/ttycontrol.c @@ -0,0 +1,57 @@ +/* ttycontrol.c - ttycontrol */ + +#include + +/*------------------------------------------------------------------------ + * ttycontrol - Control a tty device by setting modes + *------------------------------------------------------------------------ + */ +devcall ttycontrol( + struct dentry *devptr, /* Entry in device switch table */ + int32 func, /* Function to perform */ + int32 arg1, /* Argument 1 for request */ + int32 arg2 /* Argument 2 for request */ + ) +{ + struct ttycblk *typtr; /* Pointer to tty control block */ + char ch; /* Character for lookahead */ + + typtr = &ttytab[devptr->dvminor]; + + /* Process the request */ + + switch ( func ) { + + case TC_NEXTC: + wait(typtr->tyisem); + ch = *typtr->tyitail; + signal(typtr->tyisem); + return (devcall)ch; + + case TC_MODER: + typtr->tyimode = TY_IMRAW; + return (devcall)OK; + + case TC_MODEC: + typtr->tyimode = TY_IMCOOKED; + return (devcall)OK; + + case TC_MODEK: + typtr->tyimode = TY_IMCBREAK; + return (devcall)OK; + + case TC_ICHARS: + return(semcount(typtr->tyisem)); + + case TC_ECHO: + typtr->tyiecho = TRUE; + return (devcall)OK; + + case TC_NOECHO: + typtr->tyiecho = FALSE; + return (devcall)OK; + + default: + return (devcall)SYSERR; + } +} diff --git a/device/x86-galileo/tty/ttydispatch.S b/device/x86-galileo/tty/ttydispatch.S new file mode 100644 index 0000000..7c55a24 --- /dev/null +++ b/device/x86-galileo/tty/ttydispatch.S @@ -0,0 +1,21 @@ +/* ttydispatch.S - ttydispatch */ + +#include + .text + .globl ttydispatch + .globl ttyhandler + +/*------------------------------------------------------------------------ + * ttydispatch - Dispatch an interrupt to the tty handler function + *------------------------------------------------------------------------ + */ +ttydispatch: + pushal /* Save general-purpose regs. */ + pushfl /* Save the flags register */ + cli /* Prevent further interrupts */ + movb $EOI,%al /* Clear the interrupt */ + outb %al,$OCW1_2 + call ttyhandler /* Call the handler */ + popfl /* Restore the flags register */ + popal /* Restore general-purpose regs.*/ + iret /* Return from interrupt */ diff --git a/device/x86-galileo/tty/ttygetc.c b/device/x86-galileo/tty/ttygetc.c new file mode 100644 index 0000000..66ad151 --- /dev/null +++ b/device/x86-galileo/tty/ttygetc.c @@ -0,0 +1,37 @@ +/* ttygetc.c - ttygetc */ + +#include + +/*------------------------------------------------------------------------ + * ttygetc - Read one character from a tty device (interrupts disabled) + *------------------------------------------------------------------------ + */ +devcall ttygetc( + struct dentry *devptr /* Entry in device switch table */ + ) +{ + char ch; /* Character to return */ + struct ttycblk *typtr; /* Pointer to ttytab entry */ + + typtr = &ttytab[devptr->dvminor]; + + /* Wait for a character in the buffer and extract one character */ + + wait(typtr->tyisem); + ch = *typtr->tyihead++; + + /* Wrap around to beginning of buffer, if needed */ + + if (typtr->tyihead >= &typtr->tyibuff[TY_IBUFLEN]) { + typtr->tyihead = typtr->tyibuff; + } + + /* In cooked mode, check for the EOF character */ + + if ( (typtr->tyimode == TY_IMCOOKED) && (typtr->tyeof) && + (ch == typtr->tyeofch) ) { + return (devcall)EOF; + } + + return (devcall)ch; +} diff --git a/device/x86-galileo/tty/ttyhandle_in.c b/device/x86-galileo/tty/ttyhandle_in.c new file mode 100644 index 0000000..fd329cb --- /dev/null +++ b/device/x86-galileo/tty/ttyhandle_in.c @@ -0,0 +1,266 @@ +/* ttyhandle_in.c - ttyhandle_in, erase1, eputc, echoch */ + +#include + +local void erase1(struct ttycblk *, struct uart_csreg *); +local void echoch(char, struct ttycblk *, struct uart_csreg *); +local void eputc(char, struct ttycblk *, struct uart_csreg *); + +/*------------------------------------------------------------------------ + * ttyhandle_in - Handle one arriving char (interrupts disabled) + *------------------------------------------------------------------------ + */ +void ttyhandle_in ( + struct ttycblk *typtr, /* Pointer to ttytab entry */ + struct uart_csreg *csrptr /* Address of UART's CSR */ + ) +{ + char ch; /* Next char from device */ + int32 avail; /* Chars available in buffer */ + + ch = csrptr->buffer; + + /* Compute chars available */ + + avail = semcount(typtr->tyisem); + if (avail < 0) { /* One or more processes waiting*/ + avail = 0; + } + + /* Handle raw mode */ + + if (typtr->tyimode == TY_IMRAW) { + if (avail >= TY_IBUFLEN) { /* No space => ignore input */ + return; + } + + /* Place char in buffer with no editing */ + + *typtr->tyitail++ = ch; + + /* Wrap buffer pointer */ + + if (typtr->tyotail >= &typtr->tyobuff[TY_OBUFLEN]) { + typtr->tyotail = typtr->tyobuff; + } + + /* Signal input semaphore and return */ + signal(typtr->tyisem); + return; + } + + /* Handle cooked and cbreak modes (common part) */ + + if ( (ch == TY_RETURN) && typtr->tyicrlf ) { + ch = TY_NEWLINE; + } + + /* If flow control is in effect, handle ^S and ^Q */ + + if (typtr->tyoflow) { + if (ch == typtr->tyostart) { /* ^Q starts output */ + typtr->tyoheld = FALSE; + ttykickout(csrptr); + return; + } else if (ch == typtr->tyostop) { /* ^S stops output */ + typtr->tyoheld = TRUE; + return; + } + } + + typtr->tyoheld = FALSE; /* Any other char starts output */ + + if (typtr->tyimode == TY_IMCBREAK) { /* Just cbreak mode */ + + /* If input buffer is full, send bell to user */ + + if (avail >= TY_IBUFLEN) { + eputc(typtr->tyifullc, typtr, csrptr); + } else { /* Input buffer has space for this char */ + *typtr->tyitail++ = ch; + + /* Wrap around buffer */ + + if (typtr->tyitail>=&typtr->tyibuff[TY_IBUFLEN]) { + typtr->tyitail = typtr->tyibuff; + } + if (typtr->tyiecho) { /* Are we echoing chars?*/ + echoch(ch, typtr, csrptr); + } + } + return; + + } else { /* Just cooked mode (see common code above) */ + + /* Line kill character arrives - kill entire line */ + + if (ch == typtr->tyikillc && typtr->tyikill) { + typtr->tyitail -= typtr->tyicursor; + if (typtr->tyitail < typtr->tyibuff) { + typtr->tyihead += TY_IBUFLEN; + } + typtr->tyicursor = 0; + eputc(TY_RETURN, typtr, csrptr); + eputc(TY_NEWLINE, typtr, csrptr); + return; + } + + /* Erase (backspace) character */ + + if ( ((ch==typtr->tyierasec) || (ch==typtr->tyierasec2)) + && typtr->tyierase) { + if (typtr->tyicursor > 0) { + typtr->tyicursor--; + erase1(typtr, csrptr); + } + return; + } + + /* End of line */ + + if ( (ch == TY_NEWLINE) || (ch == TY_RETURN) ) { + if (typtr->tyiecho) { + echoch(ch, typtr, csrptr); + } + *typtr->tyitail++ = ch; + if (typtr->tyitail>=&typtr->tyibuff[TY_IBUFLEN]) { + typtr->tyitail = typtr->tyibuff; + } + /* Make entire line (plus \n or \r) available */ + signaln(typtr->tyisem, typtr->tyicursor + 1); + typtr->tyicursor = 0; /* Reset for next line */ + return; + } + + /* Character to be placed in buffer - send bell if */ + /* buffer has overflowed */ + + avail = semcount(typtr->tyisem); + if (avail < 0) { + avail = 0; + } + if ((avail + typtr->tyicursor) >= TY_IBUFLEN-1) { + eputc(typtr->tyifullc, typtr, csrptr); + return; + } + + /* EOF character: recognize at beginning of line, but */ + /* print and ignore otherwise. */ + + if (ch == typtr->tyeofch && typtr->tyeof) { + if (typtr->tyiecho) { + echoch(ch, typtr, csrptr); + } + if (typtr->tyicursor != 0) { + return; + } + *typtr->tyitail++ = ch; + signal(typtr->tyisem); + return; + } + + + /* Echo the character */ + + if (typtr->tyiecho) { + echoch(ch, typtr, csrptr); + } + + /* Insert in the input buffer */ + + typtr->tyicursor++; + *typtr->tyitail++ = ch; + + /* Wrap around if needed */ + + if (typtr->tyitail >= &typtr->tyibuff[TY_IBUFLEN]) { + typtr->tyitail = typtr->tyibuff; + } + return; + } +} + +/*------------------------------------------------------------------------ + * erase1 - Erase one character honoring erasing backspace + *------------------------------------------------------------------------ + */ +local void erase1( + struct ttycblk *typtr, /* Ptr to ttytab entry */ + struct uart_csreg *csrptr /* Address of UART's CSRs */ + ) +{ + char ch; /* Character to erase */ + + if ( (--typtr->tyitail) < typtr->tyibuff) { + typtr->tyitail += TY_IBUFLEN; + } + + /* Pick up char to erase */ + + ch = *typtr->tyitail; + if (typtr->tyiecho) { /* Are we echoing? */ + if (ch < TY_BLANK || ch == 0177) { /* Nonprintable */ + if (typtr->tyevis) { /* Visual cntl chars */ + eputc(TY_BACKSP, typtr, csrptr); + if (typtr->tyieback) { /* Erase char */ + eputc(TY_BLANK, typtr, csrptr); + eputc(TY_BACKSP, typtr, csrptr); + } + } + eputc(TY_BACKSP, typtr, csrptr);/* Bypass up arr*/ + if (typtr->tyieback) { + eputc(TY_BLANK, typtr, csrptr); + eputc(TY_BACKSP, typtr, csrptr); + } + } else { /* A normal character that is printable */ + eputc(TY_BACKSP, typtr, csrptr); + if (typtr->tyieback) { /* erase the character */ + eputc(TY_BLANK, typtr, csrptr); + eputc(TY_BACKSP, typtr, csrptr); + } + } + } + return; +} + +/*------------------------------------------------------------------------ + * echoch - Echo a character with visual and output crlf options + *------------------------------------------------------------------------ + */ +local void echoch( + char ch, /* Character to echo */ + struct ttycblk *typtr, /* Ptr to ttytab entry */ + struct uart_csreg *csrptr /* Address of UART's CSRs */ + ) +{ + if ((ch==TY_NEWLINE || ch==TY_RETURN) && typtr->tyecrlf) { + eputc(TY_RETURN, typtr, csrptr); + eputc(TY_NEWLINE, typtr, csrptr); + } else if ( (chtyevis) { + eputc(TY_UPARROW, typtr, csrptr);/* print ^x */ + eputc(ch+0100, typtr, csrptr); /* Make it printable */ + } else { + eputc(ch, typtr, csrptr); + } +} + +/*------------------------------------------------------------------------ + * eputc - Put one character in the echo queue + *------------------------------------------------------------------------ + */ +local void eputc( + char ch, /* Character to echo */ + struct ttycblk *typtr, /* Ptr to ttytab entry */ + struct uart_csreg *csrptr /* Address of UART's CSRs */ + ) +{ + *typtr->tyetail++ = ch; + + /* Wrap around buffer, if needed */ + + if (typtr->tyetail >= &typtr->tyebuff[TY_EBUFLEN]) { + typtr->tyetail = typtr->tyebuff; + } + ttykickout(csrptr); + return; +} diff --git a/device/x86-galileo/tty/ttyhandle_out.c b/device/x86-galileo/tty/ttyhandle_out.c new file mode 100644 index 0000000..f1f7540 --- /dev/null +++ b/device/x86-galileo/tty/ttyhandle_out.c @@ -0,0 +1,71 @@ +/* ttyhandle_out.c - ttyhandle_out */ + +#include + +/*------------------------------------------------------------------------ + * ttyhandle_out - Handle an output on a tty device by sending more + * characters to the device FIFO (interrupts disabled) + *------------------------------------------------------------------------ + */ +void ttyhandle_out( + struct ttycblk *typtr, /* Ptr to ttytab entry */ + struct uart_csreg *csrptr /* Address of UART's CSRs */ + ) +{ + + int32 ochars; /* Number of output chars sent */ + /* to the UART */ + int32 avail; /* Available chars in output buf*/ + int32 uspace; /* Space left in onboard UART */ + /* output FIFO */ + byte ier = 0; + + /* If output is currently held, simply ignore the call */ + + if (typtr->tyoheld) { + return; + } + + /* If echo and output queues empty, turn off interrupts */ + + if ( (typtr->tyehead == typtr->tyetail) && + (semcount(typtr->tyosem) >= TY_OBUFLEN) ) { + ier = csrptr->ier; + csrptr->ier = ier & ~UART_IER_ETBEI; + return; + } + + /* Initialize uspace to the size of the transmit FIFO */ + + uspace = UART_FIFO_SIZE; + + /* While onboard FIFO is not full and the echo queue is */ + /* nonempty, xmit chars from the echo queue */ + + while ( (uspace>0) && typtr->tyehead != typtr->tyetail) { + csrptr->buffer = *typtr->tyehead++; + if (typtr->tyehead >= &typtr->tyebuff[TY_EBUFLEN]) { + typtr->tyehead = typtr->tyebuff; + } + uspace--; + } + + /* While onboard FIFO is not full and the output queue is */ + /* nonempty, transmit chars from the output queue */ + + ochars = 0; + avail = TY_OBUFLEN - semcount(typtr->tyosem); + while ( (uspace>0) && (avail > 0) ) { + csrptr->buffer = *typtr->tyohead++; + if (typtr->tyohead >= &typtr->tyobuff[TY_OBUFLEN]) { + typtr->tyohead = typtr->tyobuff; + } + avail--; + uspace--; + ochars++; + } + if (ochars > 0) { + signaln(typtr->tyosem, ochars); + } + return; +} diff --git a/device/x86-galileo/tty/ttyhandler.c b/device/x86-galileo/tty/ttyhandler.c new file mode 100644 index 0000000..ea14bbd --- /dev/null +++ b/device/x86-galileo/tty/ttyhandler.c @@ -0,0 +1,77 @@ +/* ttyhandler.c - ttyhandler */ + +#include + +/*------------------------------------------------------------------------ + * ttyhandler - Handle an interrupt for a tty (serial) device + *------------------------------------------------------------------------ + */ +void ttyhandler(void) { + struct dentry *devptr; /* Address of device control blk*/ + struct ttycblk *typtr; /* Pointer to ttytab entry */ + struct uart_csreg *csrptr; /* Address of UART's CSR */ + byte iir = 0; /* Interrupt identification */ + byte lsr = 0; /* Line status */ + + + /* Get CSR address of the device (assume console for now) */ + + devptr = (struct dentry *) &devtab[CONSOLE]; + csrptr = (struct uart_csreg *) devptr->dvcsr; + + /* Obtain a pointer to the tty control block */ + + typtr = &ttytab[ devptr->dvminor ]; + + /* Decode hardware interrupt request from UART device */ + + /* Check interrupt identification register */ + iir = csrptr->iir; + if (iir & UART_IIR_IRQ) { + return; + } + + /* Decode the interrupt cause based upon the value extracted */ + /* from the UART interrupt identification register. Clear */ + /* the interrupt source and perform the appropriate handling */ + /* to coordinate with the upper half of the driver */ + + /* Decode the interrupt cause */ + + iir &= UART_IIR_IDMASK; /* Mask off the interrupt ID */ + switch (iir) { + + /* Receiver line status interrupt (error) */ + + case UART_IIR_RLSI: + return; + + /* Receiver data available or timed out */ + + case UART_IIR_RDA: + case UART_IIR_RTO: + + resched_cntl(DEFER_START); + + /* While chars avail. in UART buffer, call ttyinter_in */ + + while ( (csrptr->lsr & UART_LSR_DR) != 0) { + ttyhandle_in(typtr, csrptr); + } + + resched_cntl(DEFER_STOP); + + return; + + /* Transmitter output FIFO is empty (i.e., ready for more) */ + + case UART_IIR_THRE: + ttyhandle_out(typtr, csrptr); + return; + + /* Modem status change (simply ignore) */ + + case UART_IIR_MSC: + return; + } +} diff --git a/device/x86-galileo/tty/ttyinit.c b/device/x86-galileo/tty/ttyinit.c new file mode 100644 index 0000000..e1b3858 --- /dev/null +++ b/device/x86-galileo/tty/ttyinit.c @@ -0,0 +1,78 @@ +/* ttyinit.c - ttyinit */ + +#include + +struct ttycblk ttytab[Ntty]; + +/*------------------------------------------------------------------------ + * ttyinit - Initialize buffers and modes for a tty line + *------------------------------------------------------------------------ + */ +devcall ttyinit( + struct dentry *devptr /* Entry in device switch table */ + ) +{ + struct ttycblk *typtr; /* Pointer to ttytab entry */ + struct uart_csreg *uptr; /* Address of UART's CSRs */ + + typtr = &ttytab[ devptr->dvminor ]; + + /* Initialize values in the tty control block */ + + typtr->tyihead = typtr->tyitail = /* Set up input queue */ + &typtr->tyibuff[0]; /* as empty */ + typtr->tyisem = semcreate(0); /* Input semaphore */ + typtr->tyohead = typtr->tyotail = /* Set up output queue */ + &typtr->tyobuff[0]; /* as empty */ + typtr->tyosem = semcreate(TY_OBUFLEN); /* Output semaphore */ + typtr->tyehead = typtr->tyetail = /* Set up echo queue */ + &typtr->tyebuff[0]; /* as empty */ + typtr->tyimode = TY_IMCOOKED; /* Start in cooked mode */ + typtr->tyiecho = TRUE; /* Echo console input */ + typtr->tyieback = TRUE; /* Honor erasing bksp */ + typtr->tyevis = TRUE; /* Visual control chars */ + typtr->tyecrlf = TRUE; /* Echo CRLF for NEWLINE*/ + typtr->tyicrlf = TRUE; /* Map CR to NEWLINE */ + typtr->tyierase = TRUE; /* Do erasing backspace */ + typtr->tyierasec = TY_BACKSP; /* Primary erase char */ + typtr->tyierasec2= TY_BACKSP2; /* Alternate erase char */ + typtr->tyeof = TRUE; /* Honor eof on input */ + typtr->tyeofch = TY_EOFCH; /* End-of-file character*/ + typtr->tyikill = TRUE; /* Allow line kill */ + typtr->tyikillc = TY_KILLCH; /* Set line kill to ^U */ + typtr->tyicursor = 0; /* Start of input line */ + typtr->tyoflow = TRUE; /* Handle flow control */ + typtr->tyoheld = FALSE; /* Output not held */ + typtr->tyostop = TY_STOPCH; /* Stop char is ^S */ + typtr->tyostart = TY_STRTCH; /* Start char is ^Q */ + typtr->tyocrlf = TRUE; /* Send CRLF for NEWLINE*/ + typtr->tyifullc = TY_FULLCH; /* Send ^G when buffer */ + /* is full */ + + /* Initialize the UART */ + + uptr = (struct uart_csreg *)devptr->dvcsr; + + /* Set baud rate */ + uptr->lcr = UART_LCR_DLAB; + uptr->dlm = 0x00; + uptr->dll = 0x18; + + uptr->lcr = UART_LCR_8N1; /* 8 bit char, No Parity, 1 Stop*/ + uptr->fcr = 0x00; /* Disable FIFO for now */ + + /* Register the interrupt dispatcher for the tty device */ + + set_evec( devptr->dvirq, (uint32)devptr->dvintr ); + + /* Enable interrupts on the device: reset the transmit and */ + /* receive FIFOS, and set the interrupt trigger level */ + + uptr->fcr = UART_FCR_EFIFO | UART_FCR_RRESET | + UART_FCR_TRESET | UART_FCR_TRIG2; + + /* Start the device */ + + ttykickout(uptr); + return OK; +} diff --git a/device/x86-galileo/tty/ttykickout.c b/device/x86-galileo/tty/ttykickout.c new file mode 100644 index 0000000..4b4bb77 --- /dev/null +++ b/device/x86-galileo/tty/ttykickout.c @@ -0,0 +1,19 @@ +/* ttykickout.c - ttykickout */ + +#include + +/*------------------------------------------------------------------------ + * ttykickout - "Kick" the hardware for a tty device, causing it to + * generate an output interrupt (interrupts disabled) + *------------------------------------------------------------------------ + */ +void ttykickout( + struct uart_csreg *csrptr /* Address of UART's CSRs */ + ) +{ + /* Force the UART hardware generate an output interrupt */ + + csrptr->ier = UART_IER_ERBFI | UART_IER_ETBEI; + + return; +} diff --git a/device/x86-galileo/tty/ttyputc.c b/device/x86-galileo/tty/ttyputc.c new file mode 100644 index 0000000..f546c18 --- /dev/null +++ b/device/x86-galileo/tty/ttyputc.c @@ -0,0 +1,38 @@ +/* ttyputc.c - ttyputc */ + +#include + +/*------------------------------------------------------------------------ + * ttyputc - Write one character to a tty device (interrupts disabled) + *------------------------------------------------------------------------ + */ +devcall ttyputc( + struct dentry *devptr, /* Entry in device switch table */ + char ch /* Character to write */ + ) +{ + struct ttycblk *typtr; /* Pointer to tty control block */ + + typtr = &ttytab[devptr->dvminor]; + + /* Handle output CRLF by sending CR first */ + + if ( ch==TY_NEWLINE && typtr->tyocrlf ) { + ttyputc(devptr, TY_RETURN); + } + + wait(typtr->tyosem); /* Wait for space in queue */ + *typtr->tyotail++ = ch; + + /* Wrap around to beginning of buffer, if needed */ + + if (typtr->tyotail >= &typtr->tyobuff[TY_OBUFLEN]) { + typtr->tyotail = typtr->tyobuff; + } + + /* Start output in case device is idle */ + + ttykickout((struct uart_csreg *)devptr->dvcsr); + + return OK; +} diff --git a/device/x86-galileo/tty/ttyread.c b/device/x86-galileo/tty/ttyread.c new file mode 100644 index 0000000..88ca170 --- /dev/null +++ b/device/x86-galileo/tty/ttyread.c @@ -0,0 +1,66 @@ +/* ttyread.c - ttyread */ + +#include + +/*------------------------------------------------------------------------ + * ttyread - Read character(s) from a tty device (interrupts disabled) + *------------------------------------------------------------------------ + */ +devcall ttyread( + struct dentry *devptr, /* Entry in device switch table */ + char *buff, /* Buffer of characters */ + int32 count /* Count of character to read */ + ) +{ + struct ttycblk *typtr; /* Pointer to tty control block */ + int32 avail; /* Characters available in buff.*/ + int32 nread; /* Number of characters read */ + int32 firstch; /* First input character on line*/ + char ch; /* Next input character */ + + if (count < 0) { + return SYSERR; + } + typtr= &ttytab[devptr->dvminor]; + + if (typtr->tyimode != TY_IMCOOKED) { + + /* For count of zero, return all available characters */ + + if (count == 0) { + avail = semcount(typtr->tyisem); + if (avail == 0) { + return 0; + } else { + count = avail; + } + } + for (nread = 0; nread < count; nread++) { + *buff++ = (char) ttygetc(devptr); + } + return nread; + } + + /* Block until input arrives */ + + firstch = ttygetc(devptr); + + /* Check for End-Of-File */ + + if (firstch == EOF) { + return EOF; + } + + /* Read up to a line */ + + ch = (char) firstch; + *buff++ = ch; + nread = 1; + while ( (nread < count) && (ch != TY_NEWLINE) && + (ch != TY_RETURN) ) { + ch = ttygetc(devptr); + *buff++ = ch; + nread++; + } + return nread; +} diff --git a/device/x86-galileo/tty/ttywrite.c b/device/x86-galileo/tty/ttywrite.c new file mode 100644 index 0000000..f9f4ada --- /dev/null +++ b/device/x86-galileo/tty/ttywrite.c @@ -0,0 +1,29 @@ +/* ttywrite.c - ttywrite */ + +#include + +/*------------------------------------------------------------------------ + * ttywrite - Write character(s) to a tty device (interrupts disabled) + *------------------------------------------------------------------------ + */ +devcall ttywrite( + struct dentry *devptr, /* Entry in device switch table */ + char *buff, /* Buffer of characters */ + int32 count /* Count of character to write */ + ) +{ + /* Handle negative and zero counts */ + + if (count < 0) { + return SYSERR; + } else if (count == 0){ + return OK; + } + + /* Write count characters one at a time */ + + for (; count>0 ; count--) { + ttyputc(devptr, *buff++); + } + return OK; +}