Пример #1
0
static
int fill_cache(epicsUInt16 dev,epicsUInt16 vend)
{
  ELLNODE *cur;
  const dev_vend_entry *current;
  dev_vend_entry *next;

  for(cur=ellFirst(&dev_vend_cache); cur; cur=ellNext(cur)){
    current=CONTAINER(cur,const dev_vend_entry,node);

    /* If one device is found then all must be in cache */
    if( current->device==dev && current->vendor==vend )
      return 0;
  }

  next=malloc(sizeof(dev_vend_entry));
  if(!next)
    return S_dev_noMemory;
  next->device=dev;
  next->vendor=vend;

  if( sharedDevPCIFind(dev,vend,&devices) ){
    free(next);
    return S_dev_addressNotFound;
  }

  /* Prepend */
  ellInsert(&dev_vend_cache, NULL, &next->node);

  return 0;
}
Пример #2
0
/*
 *      devInsertAddress()
 */
static void devInsertAddress(
ELLLIST     *pRangeList,
rangeItem   *pNewRange)
{
    rangeItem   *pBefore;
    rangeItem   *pAfter;

    epicsMutexMustLock(addrListLock);
    pAfter = (rangeItem *) ellFirst (pRangeList);
    while (pAfter) {
        if (pNewRange->end < pAfter->begin) {
            break;
        }
        pAfter = (rangeItem *) ellNext (&pAfter->node);
    }

    if (pAfter) {
        pBefore = (rangeItem *) ellPrevious (&pAfter->node);
        ellInsert (pRangeList, &pBefore->node, &pNewRange->node);
    }
    else {
        ellAdd (pRangeList, &pNewRange->node);
    }
    epicsMutexUnlock(addrListLock);
}
Пример #3
0
static void inputOpenFile(inputData *pinputData,char *filename)
{
    ELLLIST	*ppathList = &pinputData->pathList;
    pathNode	*ppathNode = 0;
    inputFile	*pinputFile;
    char	*fullname = 0;
    FILE	*fp = 0;

    if(!filename) {
	fp = stdin;
    } else if((ellCount(ppathList)==0) || strchr(filename,'/')){
	fp = fopen(filename,"r");
    } else {
        ppathNode = (pathNode *)ellFirst(ppathList);
        while(ppathNode) {
	    fullname = calloc(strlen(filename)+strlen(ppathNode->directory) +2,
		sizeof(char));
	    strcpy(fullname,ppathNode->directory);
	    strcat(fullname,"/");
	    strcat(fullname,filename);
	    fp = fopen(fullname,"r");
	    if(fp) break;
	    free((void *)fullname);
	    ppathNode = (pathNode *)ellNext(&ppathNode->node);
	}
    }
    if(!fp) {
	fprintf(stderr,"Could not open %s\n",filename);
        inputErrPrint((void *)pinputData);
        exit(1);
    }
    pinputFile = calloc(1,sizeof(inputFile));
    if(ppathNode) {
	pinputFile->filename = calloc(1,strlen(fullname)+1);
	strcpy(pinputFile->filename,fullname);
	free((void *)fullname);
    } else if(filename) {
        pinputFile->filename = calloc(1,strlen(filename)+1);
        strcpy(pinputFile->filename,filename);
    } else {
	pinputFile->filename = calloc(1,strlen("stdin")+1);
	strcpy(pinputFile->filename,"stdin");
    }
    pinputFile->fp = fp;
    ellInsert(&pinputData->inputFileList,0,&pinputFile->node);
}
Пример #4
0
static void insertProvider(gtProvider *ptp, ELLLIST *plist, epicsMutexId lock)
{
    gtProvider *ptpref;

    epicsMutexMustLock(lock);

    for (ptpref = (gtProvider *)ellFirst(plist);
         ptpref; ptpref = (gtProvider *)ellNext(&ptpref->node)) {
        if (ptpref->priority > ptp->priority)
            break;
    }

    if (ptpref) {
        /* Found a provider below the new one */
        ptpref = (gtProvider *)ellPrevious(&ptpref->node);
        ellInsert(plist, &ptpref->node, &ptp->node);
    } else {
        ellAdd(plist, &ptp->node);
    }

    epicsMutexUnlock(lock);
}
Пример #5
0
static void dbMenuBody(void)
{
    dbMenu		*pnewMenu;
    dbMenu		*pMenu;
    int			nChoice;
    int			i;
    GPHENTRY		*pgphentry;

    if(duplicate) {
	duplicate = FALSE;
	return;
    }
    pnewMenu = (dbMenu *)popFirstTemp();
    pnewMenu->nChoice = nChoice = ellCount(&tempList)/2;
    pnewMenu->papChoiceName = dbCalloc(pnewMenu->nChoice,sizeof(char *));
    pnewMenu->papChoiceValue = dbCalloc(pnewMenu->nChoice,sizeof(char *));
    for(i=0; i<nChoice; i++) {
	pnewMenu->papChoiceName[i] = (char *)popFirstTemp();
	pnewMenu->papChoiceValue[i] = (char *)popFirstTemp();
    }
    if(ellCount(&tempList)) yyerrorAbort("dbMenuBody: tempList not empty");
    /* Add menu in sorted order */
    pMenu = (dbMenu *)ellFirst(&pdbbase->menuList);
    while(pMenu && strcmp(pMenu->name,pnewMenu->name) >0 )
	pMenu = (dbMenu *)ellNext(&pMenu->node);
    if(pMenu)
	ellInsert(&pdbbase->menuList,ellPrevious(&pMenu->node),&pnewMenu->node);
    else
	ellAdd(&pdbbase->menuList,&pnewMenu->node);
    pgphentry = gphAdd(pdbbase->pgpHash,pnewMenu->name,&pdbbase->menuList);
    if(!pgphentry) {
	yyerrorAbort("gphAdd failed");
    } else {
	pgphentry->userPvt = pnewMenu;
    }
}
Пример #6
0
static void addToList(struct dbCommon *precord, scan_list *psl)
{
    scan_element *pse, *ptemp;

    epicsMutexMustLock(psl->lock);
    pse = precord->spvt;
    if (pse == NULL) {
        pse = dbCalloc(1, sizeof(scan_element));
        precord->spvt = pse;
        pse->precord = precord;
    }
    pse->pscan_list = psl;
    ptemp = (scan_element *)ellFirst(&psl->list);
    while (ptemp) {
        if (ptemp->precord->phas > precord->phas) {
            ellInsert(&psl->list, ellPrevious(&ptemp->node), &pse->node);
            break;
        }
        ptemp = (scan_element *)ellNext(&ptemp->node);
    }
    if (ptemp == NULL) ellAdd(&psl->list, (void *)pse);
    psl->modified = TRUE;
    epicsMutexUnlock(psl->lock);
}
Пример #7
0
/*
 *  devInstallAddr()
 */
static long devInstallAddr (
    rangeItem *pRange, /* item on the free list to be split */
    const char *pOwnerName,
    epicsAddressType addrType,
    size_t base,
    size_t size,
    volatile void **ppPhysicalAddress)
{
    volatile void *pPhysicalAddress;
    rangeItem *pNewRange;
    size_t reqEnd = base + (size-1);
    long status;

    /*
     * does it start below the specified block
     */
    if (base < pRange->begin) {
        return S_dev_badArgument;
    }

    /*
     * does it end above the specified block
     */
    if (reqEnd > pRange->end) {
        return S_dev_badArgument;
    }

    /*
     * always map through the virtual os in case the memory
     * management is set up there
     */
    status = (*pdevLibVME->pDevMapAddr) (addrType, 0, base, 
                size, &pPhysicalAddress);
    if (status) {
        errPrintf (status, __FILE__, __LINE__, "%s base=0X%X size = 0X%X",
            epicsAddressTypeName[addrType], (unsigned int)base, (unsigned int)size);
        return status;
    }

    /*
     * set the callers variable if the pointer is supplied
     */
    if (ppPhysicalAddress) {
        *ppPhysicalAddress = pPhysicalAddress;
    }

    /*
     * does it start at the beginning of the block
     */
    if (pRange->begin == base) {
        if (pRange->end == reqEnd) {
            epicsMutexMustLock(addrListLock);
            ellDelete(&addrFree[addrType], &pRange->node);
            epicsMutexUnlock(addrListLock);
            free ((void *)pRange);
        }
        else {
            pRange->begin = base + size;
        }
    }
    /*
     * does it end at the end of the block
     */
    else if (pRange->end == reqEnd) {
        pRange->end = base-1;
    }
    /*
     * otherwise split the item on the free list
     */
    else {

        pNewRange = (rangeItem *) calloc (1, sizeof(*pRange));
        if(!pNewRange){
            return S_dev_noMemory;
        }

        pNewRange->begin = base + size;
        pNewRange->end = pRange->end;
        pNewRange->pOwnerName = "<fragmented block>";
        pNewRange->pPhysical = NULL;
        pRange->end = base - 1;

        /*
         * add the node after the old item on the free list
         * (blocks end up ordered by address)
         */
        epicsMutexMustLock(addrListLock);
        ellInsert(&addrFree[addrType], &pRange->node, &pNewRange->node);
        epicsMutexUnlock(addrListLock);
    }

    /*
     * allocate a new address range entry and add it to
     * the list
     */
    pNewRange = (rangeItem *)calloc (1, sizeof(*pRange));
    if (!pNewRange) {
        return S_dev_noMemory;
    }

    pNewRange->begin = base;
    pNewRange->end = reqEnd;
    pNewRange->pOwnerName = pOwnerName;
    pNewRange->pPhysical = pPhysicalAddress;

    devInsertAddress (&addrAlloc[addrType], pNewRange);

    return SUCCESS;
}
Пример #8
0
/*
 * Process breakpoint
 *  Returns a zero if dbProcess() is to execute
 *  record support, a one if dbProcess() is to
 *  skip over record support.  See dbProcess().
 *
 *  1.  See if there is at least a breakpoint set somewhere
 *        in precord's lockset.  If not, return immediately.
 *  2.  Check the disable flag.
 *  3.  Add entry points to the queue for future stepping and
 *        schedule new entrypoints for the continuation task.
 *  4.  Check the pact flag.
 *  5.  Check to see if there is a breakpoint set in a record, and
 *        if so, turn on stepping mode.
 *  6.  If stepping mode is set, stop and report the breakpoint.
 */
int epicsShareAPI dbBkpt(dbCommon *precord)
{
  struct LS_LIST *pnode;
  struct EP_LIST *pqe;

 /*
  *  It is crucial that operations in dbBkpt() execute
  *    in the correct order or certain features in the
  *    breakpoint handler will not work as expected.
  */

 /*
  *  Take and give a semaphore to check for breakpoints
  *	every time a record is processed.  Slow.  Thank
  *	goodness breakpoint checking is turned off during
  *	normal operation.
  */
  epicsMutexMustLock(bkpt_stack_sem);
  FIND_LOCKSET(precord, pnode);
  epicsMutexUnlock(bkpt_stack_sem);

  if (pnode == NULL) {
    /* no breakpoints in precord's lockset */
     return(0);
  }

 /* Check disable flag */
  dbGetLink(&(precord->sdis),DBR_SHORT,&(precord->disa),0,0);
  if (precord->disa == precord->disv) {
     /*
      *  Do not process breakpoints if the record is disabled,
      *    but allow disable alarms.  Alarms will be raised
      *    in dbProcess() because returning 0 allows dbProcess()
      *    to continue.  However processing will be prevented
      *    because disa and disv will be examined again in
      *    dbProcess(). Note that checking for pact will occur
      *    before checking for disa and disv in dbProcess().
      */
      return(0);
  }

 /*
  *  Queue entry points for future stepping.  The taskid comparison
  *    is used to determine if the source of processing is the
  *    continuation task or an external source. If it is an external
  *    source, queue its execution, but dump out of dbProcess without
  *    calling record support. 
  */
  if (pnode->taskid && (epicsThreadGetIdSelf() != pnode->taskid)) {
    /* CONTINUE TASK CANNOT ENTER HERE */

    /*
     *  Add an entry point to queue, if it does
     *    not already exist.
     */
     FIND_QUEUE_ENTRY(&pnode->ep_queue, pqe, precord);
 
     if (pqe == NULL) {

        pqe = (struct EP_LIST *) malloc(sizeof(struct EP_LIST));
        if (pqe == NULL)
             return(1);


        pqe->entrypoint = precord;
        pqe->count = 1;
        epicsTimeGetCurrent(&pqe->time);
        pqe->sched = 0;

#ifdef BKPT_DIAG
        printf("   BKPT> Adding entrypoint %s to queue\n", precord->name);
#endif

       /*
        *  Take semaphore, wait on continuation task
        */
        epicsMutexMustLock(bkpt_stack_sem);

       /* Add entry to queue */
        ellAdd(&pnode->ep_queue, (ELLNODE *)pqe);

        epicsMutexUnlock(bkpt_stack_sem);
     }
     else {
        if (pqe->count < MAX_EP_COUNT)
           pqe->count++;
     }

    /* check pact */
     if (! precord->pact) {
       /* schedule if pact not set */
        pqe->sched = 1;

       /*
        *  Release the semaphore, letting the continuation
        *     task begin execution of the new entrypoint.
        */ 
        epicsEventSignal(pnode->ex_sem);
     }
     return(1);
  }

 /*
  *  Don't mess with breakpoints if pact set!  Skip
  *    over rest of dbProcess() since we don't want
  *    alarms going off.  The pact flag is checked
  *    AFTER entry point queuing so that the record
  *    timing feature will work properly.
  */
  if (precord->pact)
     return(1);

 /* Turn on stepping mode if a breakpoint is found */
  if (precord->bkpt & BKPT_ON_MASK) {
     pnode->step = 1;

#ifdef BKPT_DIAG
     printf("   BKPT> Bkpt detected: %s\n", precord->name);
#endif
  }

 /*
  *  If we are currently stepping through the lockset,
  *    suspend task.
  */
  if (pnode->step) {
      printf("\n   BKPT> Stopped at:  %s  within Entrypoint:  %s\n-> ",
                 precord->name, pnode->current_ep->name);

      pnode->precord = precord;

     /* Move current lockset to top of stack */
      ellDelete(&lset_stack, (ELLNODE *)pnode);
      ellInsert(&lset_stack, NULL, (ELLNODE *)pnode);
     /*
      *  Unlock database while the task suspends itself.  This
      *   is done so that dbb() dbd() dbc() dbs() may be used
      *   when the task is suspended.  Scan tasks that also
      *   use the scan lock feature will not be hung during
      *   a breakpoint, so that records in other locksets will
      *   continue to be processed.  Cross your fingers, this
      *   might actually work !
      */
      epicsMutexUnlock(bkpt_stack_sem);
      dbScanUnlock(precord);
      epicsThreadSuspendSelf();
      dbScanLock(precord);
      epicsMutexMustLock(bkpt_stack_sem);
   }
   return(0);
}
Пример #9
0
void
seq566set(int id, int ch, int nsamp, int ord, int prio, int stop)
{
  xy566 *card=get566(id);
  ELLNODE *node, *prev;
  seqent *ent;

  if(card->fail) return;

  if(!card){
    printf("Invalid ID\n");
    card->fail=1;
    return;
  }

  if(ch<0 || ch>card->nchan){
    printf("Invalid channel (0->%d)\n",card->nchan-1);
    card->fail=1;
    return;
  }

  if(nsamp<1 || nsamp>256){
    /* This is just a first pass to catch the
     * obviously impossible.
     * The actual max number of samples will depend
     * on what other channels are used
     */
    printf("Invalid number of samples\n");
    card->fail=1;
    return;
  }

  if(stop<0 || stop>nsamp){
    printf("Stop sample must be between 0 and %u\n",nsamp);
    card->fail=1;
    return;
  }

  if(ord<0 || ord >= card->nchan){
    printf("Invalid order (1->%d)\n",card->nchan);
    card->fail=1;
    return;
  }

  if(prio<1 || prio >= card->nchan){
    printf("Invalid priority (1->%d)\n",card->nchan);
    card->fail=1;
    return;
  }

  /* Search to see that the rules are followed */
  for(node=ellFirst(&card->seq_ctor), prev=NULL;
      node;
      prev=node, node=ellNext(node)
  ){
    ent=node2seqent(node);
    if(ent->channel==ch){
      printf("Channel %d already used\n",ch);
      card->fail=1;
      return;
    }else if(ent->order == ord && ent->priority == prio){
      printf("Order %d and prio %d are already used by channel %u\n",
        ord,prio,(unsigned)ent->channel);
      card->fail=1;
      return;
    }else if(ent->order == ord && ent->nsamples != nsamp){
      printf("Order %d must have size %u\n",
        ord,(unsigned)ent->nsamples);
      card->fail=1;
      return;
    }
  }

  /* find location for insertion which maintains
   * sorted order
   */
  for(node=ellFirst(&card->seq_ctor), prev=NULL;
      node;
      prev=node, node=ellNext(node)
  ){
    ent=node2seqent(node);
    if(ent->order > ord)
      break;
    else if(ent->order == ord && ent->priority > prio)
      break;
  }

  /* node and/or prev may be NULL if this
   * entry is to be placed at the start
   * of the list
   */

  ent=malloc(sizeof(seqent));
  if(!ent){
    printf("Out of memory\n");
    card->fail=1;
    return;
  }

  ent->channel=ch;
  ent->nsamples=nsamp;
  ent->order=ord;
  ent->priority=prio;
  ent->stop=stop;

  /* Inserts between prev and node */
  ellInsert(&card->seq_ctor, prev, &ent->node);
}
Пример #10
0
static
int sharedDevPCIFind(epicsUInt16 dev,epicsUInt16 vend,ELLLIST* store)
{
  int N, ret=0, err;
  int b, d, f, region;

  /* Read config space */
  uint8_t val8;
  uint16_t val16;
  UINT32 val32;

  for(N=0; ; N++){

    osdPCIDevice *next=calloc(1,sizeof(osdPCIDevice));
    if(!next)
      return S_dev_noMemory;

    err=pci_find_device(vend,dev,N, &b, &d, &f);
    if(err){ /* No more */
      if(N==0 && devPCIDebug>=1)
        errlogPrintf("sharedDevPCIFind: found no vendor:device with %04x:%04x\n",vend,dev);
      free(next);
      break;
    }
    next->dev.bus=b;
    next->dev.device=d;
    next->dev.function=f;

    if(devPCIDebug>=1)
      errlogPrintf("sharedDevPCIFind found %d.%d.%d\n",b,d,f);

    pci_read_config_word(b,d,f,PCI_DEVICE_ID, &val16);
    next->dev.id.device=val16;

    pci_read_config_word(b,d,f,PCI_VENDOR_ID, &val16);
    next->dev.id.vendor=val16;

    pci_read_config_word(b,d,f,PCI_SUBSYSTEM_ID, &val16);
    next->dev.id.sub_device=val16;

    pci_read_config_word(b,d,f,PCI_SUBSYSTEM_VENDOR_ID, &val16);
    next->dev.id.sub_vendor=val16;

    pci_read_config_dword(b,d,f,PCI_CLASS_REVISION, &val32);
    next->dev.id.revision=val32&0xff;
    next->dev.id.pci_class=val32>>8;

    for(region=0;region<PCIBARCOUNT;region++){
      pci_read_config_dword(b,d,f,PCI_BASE_ADDRESS(region), &val32);

      next->dev.bar[region].ioport=(val32 & PCI_BASE_ADDRESS_SPACE)==PCI_BASE_ADDRESS_SPACE_IO;
      if(next->dev.bar[region].ioport){
        /* This BAR is I/O ports */
        next->dev.bar[region].below1M=0;
        next->dev.bar[region].addr64=0;

        next->base[region]=(volatile void*)( val32 & PCI_BASE_ADDRESS_IO_MASK );

        next->len[region]=0;

      }else{
        /* This BAR is memory mapped */
        next->dev.bar[region].below1M=!!(val32&PCI_BASE_ADDRESS_MEM_TYPE_1M);
        next->dev.bar[region].addr64=!!(val32&PCI_BASE_ADDRESS_MEM_TYPE_64);

        next->base[region]=(volatile void*)( val32 & PCI_BASE_ADDRESS_MEM_MASK );

        next->len[region]=0;
      }
    }

    pci_read_config_dword(b,d,f,PCI_ROM_ADDRESS, &val32);
    next->erom=(volatile void*)(val32 & PCI_ROM_ADDRESS_MASK);

    pci_read_config_byte(b,d,f,PCI_INTERRUPT_LINE, &val8);
    next->dev.irq=val8;

    if(devPCIDebug>=1)
      errlogPrintf(" as pri %04x:%04x sub %04x:%04x cls %06x\n",
                   next->dev.id.vendor, next->dev.id.device,
                   next->dev.id.sub_vendor, next->dev.id.sub_device,
                   next->dev.id.pci_class);

    ellInsert(store,NULL,&next->node);
  }

  return ret;
}
Пример #11
0
static void dbBreakBody(void)
{
    brkTable		*pnewbrkTable;
    brkInt		*paBrkInt;
    brkTable		*pbrkTable;
    int			number, down=0;
    int			i;
    GPHENTRY		*pgphentry;

    if (duplicate) {
	duplicate = FALSE;
	return;
    }
    pnewbrkTable = (brkTable *)popFirstTemp();
    number = ellCount(&tempList);
    if (number % 2) {
	yyerrorAbort("breaktable: Raw value missing");
	return;
    }
    number /= 2;
    if (number < 2) {
	yyerrorAbort("breaktable: Must have at least two points!");
	return;
    }
    pnewbrkTable->number = number;
    pnewbrkTable->paBrkInt = paBrkInt = dbCalloc(number, sizeof(brkInt));
    for (i=0; i<number; i++) {
	char	*str;
	
	str = (char *)popFirstTemp();
	epicsScanDouble(str, &paBrkInt[i].raw);
	free(str);
	
	str = (char *)popFirstTemp();
	epicsScanDouble(str, &paBrkInt[i].eng);
	free(str);
    }
    /* Compute slopes */
    for (i=0; i<number-1; i++) {
	double slope =
	  (paBrkInt[i+1].eng - paBrkInt[i].eng)/
	  (paBrkInt[i+1].raw - paBrkInt[i].raw);
	if (!dbBptNotMonotonic && slope == 0) {
	    yyerrorAbort("breaktable slope is zero");
	    return;
	}
	if (i == 0) {
	    down = (slope < 0);
	} else if (!dbBptNotMonotonic && down != (slope < 0)) {
	    yyerrorAbort("breaktable slope changes sign");
	    return;
	}
	paBrkInt[i].slope = slope;
    }
    /* Continue with last slope beyond the final point */
    paBrkInt[number-1].slope = paBrkInt[number-2].slope;
    /* Add brkTable in sorted order */
    pbrkTable = (brkTable *)ellFirst(&pdbbase->bptList);
    while (pbrkTable) {
	if (strcmp(pbrkTable->name, pnewbrkTable->name) > 0) {
	    ellInsert(&pdbbase->bptList, ellPrevious((ELLNODE *)pbrkTable),
		(ELLNODE *)pnewbrkTable);
	    break;
	}
	pbrkTable = (brkTable *)ellNext(&pbrkTable->node);
    }
    if (!pbrkTable) ellAdd(&pdbbase->bptList, &pnewbrkTable->node);
    pgphentry = gphAdd(pdbbase->pgpHash,pnewbrkTable->name,&pdbbase->bptList);
    if (!pgphentry) {
	yyerrorAbort("dbBreakBody: gphAdd failed");
	return;
    }
    pgphentry->userPvt = pnewbrkTable;
}
Пример #12
0
static
int linuxDevPCIInit(void)
{

    DIR* sysfsPci_dir=NULL;
    struct dirent* dir;
    int i;
    osdPCIDevice *osd=NULL;
    pciLock = epicsMutexMustCreate();
    int host_is_first = 0;

    pagesize=sysconf(_SC_PAGESIZE);
    if (pagesize==-1) {
        perror("Failed to get pagesize");
        goto fail;
    }

    sysfsPci_dir = opendir("/sys/bus/pci/devices");
    if (!sysfsPci_dir){
        fprintf(stderr, "Could not open /sys/bus/pci/devices!\n");
    	goto fail;
    }

    while ((dir=readdir(sysfsPci_dir))) {
        char* filename;
        FILE* file;
        int fail=0;
        int match;
        unsigned long long int start,stop,flags;
        char dname[80];

    	if (!dir->d_name || dir->d_name[0]=='.') continue; /* Skip invalid entries */

        osd=calloc(1, sizeof(osdPCIDevice));
        if (!osd) {
            errMessage(S_dev_noMemory, "Out of memory");
            goto fail;
        }
        osd->fd=-1;
        osd->cfd = -1;
        for ( i=0; i<sizeof(osd->rfd)/sizeof(osd->rfd[0]); i++ )
            osd->rfd[i] = -1;

        osd->dev.slot = DEVPCI_NO_SLOT;

        match = sscanf(dir->d_name,"%x:%x:%x.%x",
                       &osd->dev.domain,&osd->dev.bus,&osd->dev.device,&osd->dev.function);
        if (match != 4){
            fprintf(stderr, "Could not decode PCI device directory %s\n", dir->d_name);
        }
 
        osd->dev.id.vendor=read_sysfs(&fail, BUSBASE "vendor",
                             osd->dev.domain, osd->dev.bus, osd->dev.device, osd->dev.function);
        osd->dev.id.device=read_sysfs(&fail, BUSBASE "device",
                             osd->dev.domain, osd->dev.bus, osd->dev.device, osd->dev.function);
        osd->dev.id.sub_vendor=read_sysfs(&fail, BUSBASE "subsystem_vendor",
                             osd->dev.domain, osd->dev.bus, osd->dev.device, osd->dev.function);
        osd->dev.id.sub_device=read_sysfs(&fail, BUSBASE "subsystem_device",
                             osd->dev.domain, osd->dev.bus, osd->dev.device, osd->dev.function);
        osd->dev.id.pci_class=read_sysfs(&fail, BUSBASE "class",
                             osd->dev.domain, osd->dev.bus, osd->dev.device, osd->dev.function);
        osd->dev.irq=read_sysfs(&fail, BUSBASE "irq",
                             osd->dev.domain, osd->dev.bus, osd->dev.device, osd->dev.function);
        osd->dev.id.revision=0;

        if (fail) {
            fprintf(stderr, "Warning: Failed to read some attributes of PCI device %04x:%02x:%02x.%x\n"
                         "         This may cause some searches to fail\n",
                         osd->dev.domain, osd->dev.bus, osd->dev.device, osd->dev.function);
            fail=0;
        }

        if(devPCIDebug>=1) {
            fprintf(stderr, "linuxDevPCIInit found %04x:%02x:%02x.%x\n",
                         osd->dev.domain, osd->dev.bus, osd->dev.device, osd->dev.function);
            fprintf(stderr, " as pri %04x:%04x sub %04x:%04x cls %06x\n",
                         osd->dev.id.vendor, osd->dev.id.device,
                         osd->dev.id.sub_vendor, osd->dev.id.sub_device,
                         osd->dev.id.pci_class);
        }

        /* Read BAR info */

        /* Base address */
        
        filename = allocPrintf(BUSBASE "resource",
                         osd->dev.domain, osd->dev.bus, osd->dev.device, osd->dev.function);
        if (!filename) {
            errMessage(S_dev_noMemory, "Out of memory");
            goto fail;
        }
        file=fopen(filename, "r");
        if (!file) {
            fprintf(stderr, "Could not open resource file %s!\n", filename);
            free(filename);
            continue;
        }
        for (i=0; i<PCIBARCOUNT; i++) { /* read 6 BARs */
            match = fscanf(file, "0x%16llx 0x%16llx 0x%16llx\n", &start, &stop, &flags);
        
            if (match != 3) {
                fprintf(stderr, "Could not parse line %i of %s\n", i+1, filename);
                continue;
            }

            osd->dev.bar[i].ioport = (flags & PCI_BASE_ADDRESS_SPACE)==PCI_BASE_ADDRESS_SPACE_IO;
            osd->dev.bar[i].below1M = !!(flags&PCI_BASE_ADDRESS_MEM_TYPE_1M);
            osd->dev.bar[i].addr64 = !!(flags&PCI_BASE_ADDRESS_MEM_TYPE_64);
            osd->displayBAR[i] = start;

            /* offset from start of page to start of BAR */
            osd->offset[i] = osd->displayBAR[i]&(pagesize-1);
            /* region length */
            osd->len[i] = (start || stop ) ? (stop - start + 1) : 0;
        }
        /* rom */
        match = fscanf(file, "%llx %llx %llx\n", &start, &stop, &flags);
        if (match != 3) {
            fprintf(stderr, "Could not parse line %i of %s\n", i+1, filename);
            start = 0;
            stop = 0;
        }

        osd->displayErom = start;
        osd->eromlen = (start || stop ) ? (stop - start + 1) : 0;
        
        fclose(file);
        free(filename);
        
        /* driver name */
        filename = allocPrintf(BUSBASE "driver",
                         osd->dev.domain, osd->dev.bus, osd->dev.device, osd->dev.function);
        if (!filename) {
            errMessage(S_dev_noMemory, "Out of memory");
            goto fail;
        }
        memset (dname, 0, sizeof(dname));
        if (readlink(filename, dname, sizeof(dname)-1) != -1)
            osd->dev.driver = epicsStrDup(basename(dname));
        free(filename);

        osd->devLock = epicsMutexMustCreate();

        if (!ellCount(&devices))
        {
            host_is_first = (osd->dev.bus == 0 && osd->dev.device == 0);
        }
        ellInsert(&devices,host_is_first?ellLast(&devices):NULL,&osd->node);
        osd=NULL;
    }
    if (sysfsPci_dir)
        closedir(sysfsPci_dir);

    sysfsPci_dir = opendir(linuxslotsdir);
    if (sysfsPci_dir){
        while ((dir=readdir(sysfsPci_dir))) {
            unsigned dom, B, D;
            char *fullname;
            FILE *fp;

            if (!dir->d_name || dir->d_name[0]=='.') continue; /* Skip invalid entries */
            if(devPCIDebug>4)
                fprintf(stderr, "examine /slots entry '%s'\n", dir->d_name);

            fullname = allocPrintf("%s/%s/address", linuxslotsdir, dir->d_name);
            if(!fullname) continue;

            if(devPCIDebug>3)
                fprintf(stderr, "found '%s'\n", fullname);

            if((fp=fopen(fullname, "r"))!=NULL) {

                if(fscanf(fp, "%x:%x:%x", &dom, &B, &D)==3) {
                    ELLNODE *cur;
                    if(devPCIDebug>2)
                        fprintf(stderr, "found slot %s with %04u:%02u:%02u.*\n", dir->d_name, dom, B, D);

                    for(cur=ellFirst(&devices); cur; cur=ellNext(cur)) {
                        osdPCIDevice *osd = CONTAINER(cur, osdPCIDevice, node);
                        if(osd->dev.domain!=dom || osd->dev.bus!=B || osd->dev.device!=D)
                            continue;
                        if(osd->dev.slot==DEVPCI_NO_SLOT) {
                            osd->dev.slot = strdup(dir->d_name); // return NULL would mean slot remains unlabeled
                        } else {
                            fprintf(stderr, "Duplicate slot address for %s\n", dir->d_name);
                        }
                    }
                }

                fclose(fp);
            }
            free(fullname);
        }
        closedir(sysfsPci_dir);
    } else if(devPCIDebug>0) {
        fprintf(stderr, "/sys does not provide PCI slots listing\n");
    }


    return 0;
fail:
    if (sysfsPci_dir)
        closedir(sysfsPci_dir);
    epicsMutexDestroy(pciLock);
    return S_dev_badInit;
}