static int i82092aa_set_mem_map()

in i82092.c [589:662]


static int i82092aa_set_mem_map(struct pcmcia_socket *socket,
				struct pccard_mem_map *mem)
{
	struct socket_info *sock_info = container_of(socket, struct socket_info,
						     socket);
	unsigned int sock = sock_info->number;
	struct pci_bus_region region;
	unsigned short base, i;
	unsigned char map;

	pcibios_resource_to_bus(sock_info->dev->bus, &region, mem->res);

	map = mem->map;
	if (map > 4)
		return -EINVAL;

	if ((mem->card_start > 0x3ffffff) || (region.start > region.end) ||
	     (mem->speed > 1000)) {
		dev_err(&sock_info->dev->dev,
			"invalid mem map for socket %i: %llx to %llx with a start of %x\n",
			sock,
			(unsigned long long)region.start,
			(unsigned long long)region.end,
			mem->card_start);
		return -EINVAL;
	}

	/* Turn off the window before changing anything */
	if (indirect_read(sock, I365_ADDRWIN) & I365_ENA_MEM(map))
		indirect_resetbit(sock, I365_ADDRWIN, I365_ENA_MEM(map));

	/* write the start address */
	base = I365_MEM(map);
	i = (region.start >> 12) & 0x0fff;
	if (mem->flags & MAP_16BIT)
		i |= I365_MEM_16BIT;
	if (mem->flags & MAP_0WS)
		i |= I365_MEM_0WS;
	indirect_write16(sock, base+I365_W_START, i);

	/* write the stop address */

	i = (region.end >> 12) & 0x0fff;
	switch (to_cycles(mem->speed)) {
	case 0:
		break;
	case 1:
		i |= I365_MEM_WS0;
		break;
	case 2:
		i |= I365_MEM_WS1;
		break;
	default:
		i |= I365_MEM_WS1 | I365_MEM_WS0;
		break;
	}

	indirect_write16(sock, base+I365_W_STOP, i);

	/* card start */

	i = ((mem->card_start - region.start) >> 12) & 0x3fff;
	if (mem->flags & MAP_WRPROT)
		i |= I365_MEM_WRPROT;
	if (mem->flags & MAP_ATTRIB)
		i |= I365_MEM_REG;
	indirect_write16(sock, base+I365_W_OFF, i);

	/* Enable the window if necessary */
	if (mem->flags & MAP_ACTIVE)
		indirect_setbit(sock, I365_ADDRWIN, I365_ENA_MEM(map));

	return 0;
}