/* Copyright (c) 2016, Texas Instruments Incorporated - http://www.ti.com/ All rights reserved. * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * Neither the name of Texas Instruments Incorporated nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ /* * ======== dev2.c ======== */ #include #include #include #include #include #include #include #include "dev2.h" #include Queue_Elem devList = {NULL, NULL}; DEV2_Attrs DEV2_ATTRS = { NULL, /* dev ID */ NULL, /* params */ DEV2_SIOTYPE, /* TODO: Default was set to IOM(fxns) */ NULL /* devp */ }; static Bool devInit = FALSE; /* * ======== DEV2_createDevice ======== * Create a device(DEV2_Device) entry and add it to the list of devices. * This API is not reentrant */ Int DEV2_createDevice (String name, Void *fxns, Fxn initFxn, DEV2_Attrs *attrs) { // DEV2_TableElem *objDevHead = (DEV2_TableElem*) &DEV2_table; DEV2_TableElem *objDevHead = (DEV2_TableElem*) &devList; DEV2_TableElem *objDev, *objEntry; DEV2_Device *dptr, *entry; // IOM_Fxns *iomfxns; // Int status; UInt key; UInt taskKey; Error_Block eb; DEV2_init(); /* Crate a device entry */ Error_init(&eb); objEntry = Memory_calloc(0, sizeof(DEV2_TableElem), 0, &eb); if (objEntry == NULL) { return(DEV2_ENOMEM); } taskKey = Task_disable(); /* * Return error if device already exists in the Device table, or has * already been created. */ DEV2_find(name, &entry); if (entry != NULL) { Task_restore(taskKey); Memory_free(0, objEntry, sizeof(DEV2_TableElem)); Log_error1("DEV2_createDevice: Device %s alread in table", (IArg)name); return (DEV2_EINVAL); } /* * Initialize new device entry(DEV2_Device) in the OBJ table with * the parameters passed to API */ entry = &objEntry->device; entry->name = name; entry->fxns = fxns; if (attrs == NULL) { attrs = &DEV2_ATTRS; } entry->devid = attrs->devid; entry->params = attrs->params; entry->type = attrs->type; entry->devp = attrs->devp; /* * Call the Device init function if its not NULL, with interrupts * disabled. */ if (initFxn != NULL) { key = Hwi_disable(); (*initFxn)(); Hwi_restore(key); } #if 0 // TODO /* * If device created is of type IOM then call mini driver function * mdBindDev with interrupts disabled. */ if (entry->type == DEV2_IOMTYPE) { iomfxns = (IOM_Fxns *)entry->fxns; key = HWI_disable(); status = iomfxns->mdBindDev(&entry->devp, entry->devid, entry->params); HWI_restore(key); if (status != IOM_COMPLETED) { TSK_enable(); /* Delete the just created device entry in device table */ Memory_free(NULL, objEntry, sizeof(DEV2_TableElem)); Log_error1("DEV2_createDevice: mdBindDev() failed (%d)", (IArg)status); return(status); } } #endif // TODO /* * Device is ready for addition into the device. Check new device * name length against existing device name lengths. If length of * new device is greater than one in the table, mark the location * and insert device ahead of device whose name length is shorter * else add it to the end. * * This will keep all the devices sorted in descending order, which is * required to pass additional parameters along with device name in * DEV2_open() */ objDev = (DEV2_TableElem *)Queue_next((Ptr)objDevHead); while (objDev != objDevHead) { dptr = &objDev->device; if (strlen(name) > strlen(dptr->name)) { break; } objDev = (DEV2_TableElem *)Queue_next((Ptr)objDev); } /* Insert objEntry ahead of objDev */ Queue_insert((Queue_Elem *)objDev, (Queue_Elem *)objEntry); Task_restore(taskKey); return (DEV2_OK); } /* * DEV2_deleteDevice deletes device(DEV2_Device) entry in the OBJ table * if device by that name exist in the system. * This API is not reentrant */ Int DEV2_deleteDevice (String name) { DEV2_TableElem *objDev; DEV2_Device *entry; // TODO IOM_Fxns *iomfxns; Int status = DEV2_OK; // Uns key; DEV2_init(); /* Check if device exists in the Device table, if not return FALSE */ DEV2_find(name, &entry); if (entry == NULL) { Log_error1("DEV2_deleteDevice: Device %s not found", (IArg)name); return (DEV2_ENODEV); } #if 0 // TODO /* * If device to be deleted is of type IOM call mdUnBindDev with * interrupts disabled */ if (entry->type == DEV2_IOMTYPE) { iomfxns = (IOM_Fxns *)entry->fxns; key = Hwi_disable(); status = iomfxns->mdUnBindDev(entry->devp); Hwi_restore(key); if (status != IOM_COMPLETED) { Log_error1("DEV2_deleteDevice: mdUnBindDev failed (%d) ", status); } else { status = DEV2_OK; } } #endif // TODO /* Free Device entry in the device table */ objDev = (DEV2_TableElem *)((char *)entry - sizeof(Queue_Elem)); Queue_remove((Queue_Elem *)objDev); Memory_free(NULL, objDev, sizeof(DEV2_TableElem)); return (status); } /* * ======== DEV2_ebadio ======== */ Int DEV2_ebadio(DEV2_Handle device) { Log_error1("DEV2_ebadio (0x%x)", (IArg)device); return (DEV2_EBADIO); } /* * ======== DEV2_find ======== */ Void DEV2_find(String name, DEV2_Device **driver) { DEV2_TableElem *objDevHead = (DEV2_TableElem*) &devList; // DEV2_TableElem *objDevHead = (DEV2_TableElem*) &DEV2_table; DEV2_TableElem *objDev; DEV2_Device *dptr; DEV2_init(); /* * Do the exact match, return device entry if successfull. */ for (objDev = (DEV2_TableElem *)Queue_next((Ptr)objDevHead); objDev != objDevHead; objDev = (DEV2_TableElem *)Queue_next((Ptr)objDev)) { dptr = &objDev->device; if (strcmp(name,dptr->name) == 0) { /* If driver exists in the devicetable, point the *driver to corresponding device entry */ *driver = dptr; return; } } *driver = NULL; return; } /* * ======== DEV2_init ======== */ Void DEV2_init() { UInt taskKey; UInt numEntries = 0; Int i; if (!devInit) { taskKey = Task_disable(); /* Count the number of devices and initialize next, prev pointers */ for (i = 0; DEV2_table[i].device.name != NULL; i++) { DEV2_table[i].qElem.next = (Queue_Elem *)&DEV2_table[i + 1]; DEV2_table[i + 1].qElem.prev = (Queue_Elem *)&DEV2_table[i]; } numEntries = i; if (numEntries > 0) { devList.next = (Queue_Elem *)&DEV2_table[0]; devList.prev = (Queue_Elem *)&DEV2_table[numEntries - 1]; DEV2_table[numEntries - 1].qElem.next = &devList; } else { devList.next = devList.prev = &devList; } devInit = TRUE; Task_restore(taskKey); } } /* * ======== DEV2_match ======== */ String DEV2_match(String name, DEV2_Device **driver) { DEV2_TableElem *objDevHead = (DEV2_TableElem*)&devList; // DEV2_TableElem *objDevHead = (DEV2_TableElem*) &DEV2_table; DEV2_TableElem *objDev; DEV2_Device *dptr; Int len; DEV2_init(); /* * Trace the existence of device through OBJ_table[OBJ_DEV]. * If successfull *dptr points to the device entry. */ if(name[0] == '/') name ++; if (strncmp(name, "SAP", 3) == 0) name[0]='D'; for (objDev = (DEV2_TableElem *)Queue_next((Ptr)objDevHead); objDev != objDevHead; objDev = (DEV2_TableElem *)Queue_next((Ptr)objDev)) { dptr = &objDev->device; len = strlen(dptr->name); if ((len == 0) || (strncmp(name,dptr->name,len) == 0) ) { /* If driver exists in the devicetable, point the *driver to corresponding device entry */ *driver = dptr; return (name + len); } } *driver = NULL; return (name); } /* * ======== DEV2_mkframe ======== */ DEV2_Frame *DEV2_mkframe(xdc_runtime_IHeap_Handle seg, Uns size, Uns align) { DEV2_Frame *frame; Error_Block eb; Error_init(&eb); if ((frame = Memory_alloc(0, sizeof(DEV2_Frame), 0, &eb)) == NULL) { return (NULL); } /* don't allocate frame buffer if size is zero */ if (size > 0) { if ((frame->addr = Memory_alloc(seg, size, align, &eb)) == NULL) { Memory_free(0, frame, sizeof(DEV2_Frame)); return (NULL); } } frame->size = size; return (frame); } /* * ======== DEV2_one ======== */ Int DEV2_one(void) { return (1); } /* * ======== DEV2_rmframe ======== */ Void DEV2_rmframe(DEV2_Frame *frame, xdc_runtime_IHeap_Handle seg, Uns size) { if (size > 0) { /* free buffer */ Memory_free(seg, frame->addr, size); } /* free object */ Memory_free(0, frame, sizeof(DEV2_Frame)); } /* * ======== DEV2_zero ======== */ Int DEV2_zero(void) { return (0); }