in bridges/vme_fake.c [516:613]
static ssize_t fake_master_read(struct vme_master_resource *image, void *buf,
size_t count, loff_t offset)
{
int retval;
u32 aspace, cycle, dwidth;
struct vme_bridge *fake_bridge;
struct fake_driver *priv;
int i;
unsigned long long addr;
unsigned int done = 0;
unsigned int count32;
fake_bridge = image->parent;
priv = fake_bridge->driver_priv;
i = image->number;
addr = (unsigned long long)priv->masters[i].vme_base + offset;
aspace = priv->masters[i].aspace;
cycle = priv->masters[i].cycle;
dwidth = priv->masters[i].dwidth;
spin_lock(&image->lock);
/* The following code handles VME address alignment. We cannot use
* memcpy_xxx here because it may cut data transfers in to 8-bit
* cycles when D16 or D32 cycles are required on the VME bus.
* On the other hand, the bridge itself assures that the maximum data
* cycle configured for the transfer is used and splits it
* automatically for non-aligned addresses, so we don't want the
* overhead of needlessly forcing small transfers for the entire cycle.
*/
if (addr & 0x1) {
*(u8 *)buf = fake_vmeread8(priv, addr, aspace, cycle);
done += 1;
if (done == count)
goto out;
}
if ((dwidth == VME_D16) || (dwidth == VME_D32)) {
if ((addr + done) & 0x2) {
if ((count - done) < 2) {
*(u8 *)(buf + done) = fake_vmeread8(priv,
addr + done, aspace, cycle);
done += 1;
goto out;
} else {
*(u16 *)(buf + done) = fake_vmeread16(priv,
addr + done, aspace, cycle);
done += 2;
}
}
}
if (dwidth == VME_D32) {
count32 = (count - done) & ~0x3;
while (done < count32) {
*(u32 *)(buf + done) = fake_vmeread32(priv, addr + done,
aspace, cycle);
done += 4;
}
} else if (dwidth == VME_D16) {
count32 = (count - done) & ~0x3;
while (done < count32) {
*(u16 *)(buf + done) = fake_vmeread16(priv, addr + done,
aspace, cycle);
done += 2;
}
} else if (dwidth == VME_D8) {
count32 = (count - done);
while (done < count32) {
*(u8 *)(buf + done) = fake_vmeread8(priv, addr + done,
aspace, cycle);
done += 1;
}
}
if ((dwidth == VME_D16) || (dwidth == VME_D32)) {
if ((count - done) & 0x2) {
*(u16 *)(buf + done) = fake_vmeread16(priv, addr + done,
aspace, cycle);
done += 2;
}
}
if ((count - done) & 0x1) {
*(u8 *)(buf + done) = fake_vmeread8(priv, addr + done, aspace,
cycle);
done += 1;
}
out:
retval = count;
spin_unlock(&image->lock);
return retval;
}