/** * * Identify the CompactFlash device. Retrieves the parameters for the * CompactFlash storage device. Note that this is a polled read of one sector * of data. The data is read from the CompactFlash into a byte buffer, which * is then copied into the XSysAce_CFParameters structure passed in by the * user. The copy is necessary since we don't know how the compiler packs * the XSysAce_CFParameters structure. * * An MPU lock, obtained using XSysAce_Lock(), must be granted before calling * this function. If a lock has not been granted, no action is taken and an * error is returned. * * @param InstancePtr is a pointer to the XSysAce instance . * @param ParamPtr is a pointer to a XSysAce_CFParameters structure where * the information for the CompactFlash device will be stored. See * xsysace.h for details on the XSysAce_CFParameters structure. * * @return * - XST_SUCCESS if the identify was done successfully * - XST_FAILURE if an error occurs. Use XSysAce_GetErrors() to * determine cause. * - XST_SYSACE_NO_LOCK if no MPU lock has yet been granted * - XST_DEVICE_BUSY if the CompactFlash is not ready for a command * * @note None. * * @internal * * The identify command has the same protocol as the read sector command * according to the CompactFlash specification. However, there is a discepency * in that same specification on the size of the parameter structure. The word * addresses defined in the spec indicate the parameter information is a full * 512 bytes, the same size as a sector. The total bytes defined in the spec, * however, indicate that the parameter information is only 500 bytes. We * defined the parameter structure in xsysace.h assuming the parameters are the * full 512 bytes since that makes sense, and therefore ignored the "Total * Bytes" column in the spec. * * The SectorData variable was made static to avoid putting 512 bytes on the * stack every time this function is called. * ******************************************************************************/ int XSysAce_IdentifyCF(XSysAce *InstancePtr, XSysAce_CFParameters * ParamPtr) { int NumRead; u32 InterruptsOn; static u8 SectorData[XSA_CF_SECTOR_SIZE]; Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(ParamPtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); /* If a lock has not been granted, return an error */ if (!XSysAce_IsMpuLocked(InstancePtr->BaseAddress)) { return XST_SYSACE_NO_LOCK; } /* See if the CF is ready for a command */ if (!XSysAce_IsReadyForCmd(InstancePtr->BaseAddress)) { return XST_DEVICE_BUSY; } /* * If interrupts are enabled, we disable them because we want to do this * identify in polled mode - due to the buffer endian conversion and copy * that takes place. */ InterruptsOn = XSysAce_IsIntrEnabled(InstancePtr->BaseAddress); if (InterruptsOn) { XSysAce_DisableInterrupt(InstancePtr); } /* * Send the identify command */ XSysAce_RegWrite16(InstancePtr->BaseAddress + XSA_SCCR_OFFSET, XSA_SCCR_IDENTIFY_MASK); /* Reset configuration controller (be sure to keep the lock) */ /* This breaks mvl, beware! */ /* XSysAce_OrControlReg(InstancePtr->BaseAddress, XSA_CR_CFGRESET_MASK); */ /* * Read a sector of data from the data buffer. The parameter info is * the same size as a sector. */ NumRead = XSysAce_ReadDataBuffer(InstancePtr->BaseAddress, SectorData, XSA_CF_SECTOR_SIZE); /* Clear reset of configuration controller */ /* This breaks mvl, beware! */ /*XSysAce_AndControlReg(InstancePtr->BaseAddress, ~(XSA_CR_CFGRESET_MASK)); */ /* If interrupts were on, re-enable interrupts (regardless of error) */ if (InterruptsOn) { XSysAce_EnableInterrupt(InstancePtr); } if (NumRead == 0) { /* an error occurred */ return XST_FAILURE; } /* * Copy the byte buffer to the parameter structure */ FillParam(ParamPtr, SectorData); return XST_SUCCESS; }
static int xsysace_probe(struct device *dev) { XSysAce_Config xsysace_cfg; struct platform_device *pdev = to_platform_device(dev); struct resource *irq_res, *regs_res; unsigned long remap_size; XStatus stat; long size; XSysAce_CFParameters ident; int retval; if (!dev) return -EINVAL; /* Find irq number, map the control registers in */ irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); regs_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!regs_res || !irq_res) { printk(KERN_ERR "%s #%d: IO resource(s) not found\n", DRIVER_NAME, pdev->id); retval = -EFAULT; goto failed1; } xsa_irq = irq_res->start; xsa_phys_addr = regs_res->start; remap_size = regs_res->end - regs_res->start + 1; if (!request_mem_region(regs_res->start, remap_size, DRIVER_NAME)) { printk(KERN_ERR "%s #%d: Couldn't lock memory region at 0x%08lX\n", DRIVER_NAME, pdev->id, regs_res->start); retval = -EBUSY; goto failed1; } /* Fill in cfg data and add them to the list */ xsa_remap_size = remap_size; xsysace_cfg.DeviceId = pdev->id; xsysace_cfg.BaseAddress = (u32) ioremap(regs_res->start, remap_size); if (xsysace_cfg.BaseAddress == 0) { printk(KERN_ERR "%s #%d: Couldn't ioremap memory at 0x%08lX\n", DRIVER_NAME, pdev->id, regs_res->start); retval = -EFAULT; goto failed2; } /* Tell the Xilinx code to bring this SystemACE interface up. */ down(&cfg_sem); if (XSysAce_CfgInitialize (&SysAce, &xsysace_cfg, xsysace_cfg.BaseAddress) != XST_SUCCESS) { up(&cfg_sem); printk(KERN_ERR "%s #%d: Could not initialize device.\n", DRIVER_NAME, pdev->id); retval = -ENODEV; goto failed3; } up(&cfg_sem); retval = request_irq(xsa_irq, xsysace_interrupt, 0, DEVICE_NAME, NULL); if (retval) { printk(KERN_ERR "%s #%d: Couldn't allocate interrupt %d.\n", DRIVER_NAME, pdev->id, xsa_irq); goto failed3; } XSysAce_SetEventHandler(&SysAce, EventHandler, (void *)NULL); XSysAce_EnableInterrupt(&SysAce); /* Time to identify the drive. */ while (XSysAce_Lock(&SysAce, 0) == XST_DEVICE_BUSY) ; while ((stat = XSysAce_IdentifyCF(&SysAce, &ident)) == XST_DEVICE_BUSY) ; XSysAce_Unlock(&SysAce); if (stat != XST_SUCCESS) { printk(KERN_ERR "%s: Could not send identify command.\n", DEVICE_NAME); retval = -ENODEV; goto failed4; } /* Fill in what we learned. */ heads = ident.NumHeads; sectors = ident.NumSectorsPerTrack; cylinders = ident.NumCylinders; size = (long)cylinders *(long)heads *(long)sectors; xsysace_queue = blk_init_queue(xsysace_do_request, &xsysace_lock); if (!xsysace_queue) { retval = -ENODEV; goto failed4; } if (register_blkdev(xsa_major, MAJOR_NAME)) { retval = -EBUSY; goto failed5; } xsa_gendisk = alloc_disk(16); if (!xsa_gendisk) { retval = -ENODEV; goto failed6; } strcpy(xsa_gendisk->disk_name, MAJOR_NAME); xsa_gendisk->fops = &xsysace_fops; xsa_gendisk->major = xsa_major; xsa_gendisk->first_minor = 0; xsa_gendisk->minors = 16; xsa_gendisk->queue = xsysace_queue; set_capacity(xsa_gendisk, size); printk(KERN_INFO "%s at 0x%08X mapped to 0x%08X, irq=%d, %ldKB\n", DEVICE_NAME, xsa_phys_addr, SysAce.BaseAddress, xsa_irq, size / 2); /* Hook our reset function into system's restart code. */ if (old_restart == NULL) { old_restart = ppc_md.restart; ppc_md.restart = xsysace_restart; } if (proc_init()) printk(KERN_WARNING "%s: could not register /proc interface.\n", DEVICE_NAME); add_disk(xsa_gendisk); return 0; /* success */ failed6: unregister_blkdev(xsa_major, MAJOR_NAME); failed5: blk_cleanup_queue(xsysace_queue); failed4: XSysAce_DisableInterrupt(&SysAce); free_irq(xsa_irq, NULL); failed3: iounmap((void *)(xsysace_cfg.BaseAddress)); failed2: release_mem_region(regs_res->start, remap_size); failed1: return retval; }