vme.c revision 58e507987b285f3df99f839c79da3985555ac220
1a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
2a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * VME Bridge Framework
3a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch *
4a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Author: Martyn Welch <martyn.welch@gefanuc.com>
5a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Copyright 2008 GE Fanuc Intelligent Platforms Embedded Systems, Inc.
6a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch *
7a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Based on work by Tom Armistead and Ajit Prem
8a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Copyright 2004 Motorola Inc.
9a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch *
10a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * This program is free software; you can redistribute  it and/or modify it
11a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * under  the terms of  the GNU General  Public License as published by the
12a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Free Software Foundation;  either version 2 of the  License, or (at your
13a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * option) any later version.
14a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
15a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
16a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include <linux/module.h>
17a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include <linux/moduleparam.h>
18a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include <linux/mm.h>
19a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include <linux/types.h>
20a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include <linux/kernel.h>
21a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include <linux/errno.h>
22a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include <linux/pci.h>
23a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include <linux/poll.h>
24a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include <linux/highmem.h>
25a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include <linux/interrupt.h>
26a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include <linux/pagemap.h>
27a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include <linux/device.h>
28a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include <linux/dma-mapping.h>
29a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include <linux/syscalls.h>
30400822fec46ce69d2ba7692689a1689653f7b847Martyn Welch#include <linux/mutex.h>
31a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include <linux/spinlock.h>
32a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
33a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include "vme.h"
34a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch#include "vme_bridge.h"
35a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
36400822fec46ce69d2ba7692689a1689653f7b847Martyn Welch/* Bitmask and mutex to keep track of bridge numbers */
37a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstatic unsigned int vme_bus_numbers;
38400822fec46ce69d2ba7692689a1689653f7b847Martyn WelchDEFINE_MUTEX(vme_bus_num_mtx);
39a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
40a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstatic void __exit vme_exit (void);
41a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstatic int __init vme_init (void);
42a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
43a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
44a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
45a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Find the bridge resource associated with a specific device resource
46a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
47a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstatic struct vme_bridge *dev_to_bridge(struct device *dev)
48a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
49a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return dev->platform_data;
50a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
51a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
52a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
53a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Find the bridge that the resource is associated with.
54a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
55a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstatic struct vme_bridge *find_bridge(struct vme_resource *resource)
56a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
57a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Get list to search */
58a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	switch (resource->type) {
59a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_MASTER:
60a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return list_entry(resource->entry, struct vme_master_resource,
61a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			list)->parent;
62a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
63a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_SLAVE:
64a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return list_entry(resource->entry, struct vme_slave_resource,
65a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			list)->parent;
66a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
67a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_DMA:
68a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return list_entry(resource->entry, struct vme_dma_resource,
69a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			list)->parent;
70a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
7142fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	case VME_LM:
7242fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		return list_entry(resource->entry, struct vme_lm_resource,
7342fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch			list)->parent;
7442fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		break;
75a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	default:
76a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_ERR "Unknown resource type\n");
77a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return NULL;
78a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
79a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
80a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
81a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
82a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
83a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Allocate a contiguous block of memory for use by the driver. This is used to
84a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * create the buffers for the slave windows.
85a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch *
86a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * XXX VME bridges could be available on buses other than PCI. At the momment
87a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch *     this framework only supports PCI devices.
88a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
89a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchvoid * vme_alloc_consistent(struct vme_resource *resource, size_t size,
90a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	dma_addr_t *dma)
91a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
92a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge;
93a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct pci_dev *pdev;
94a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
95a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if(resource == NULL) {
96a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk("No resource\n");
97a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return NULL;
98a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
99a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
100a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	bridge = find_bridge(resource);
101a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if(bridge == NULL) {
102a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk("Can't find bridge\n");
103a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return NULL;
104a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
105a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
106a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Find pci_dev container of dev */
107a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge->parent == NULL) {
108a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk("Dev entry NULL\n");
109a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return NULL;
110a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
111a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	pdev = container_of(bridge->parent, struct pci_dev, dev);
112a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
113a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return pci_alloc_consistent(pdev, size, dma);
114a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
115a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_alloc_consistent);
116a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
117a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
118a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Free previously allocated contiguous block of memory.
119a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch *
120a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * XXX VME bridges could be available on buses other than PCI. At the momment
121a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch *     this framework only supports PCI devices.
122a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
123a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchvoid vme_free_consistent(struct vme_resource *resource, size_t size,
124a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	void *vaddr, dma_addr_t dma)
125a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
126a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge;
127a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct pci_dev *pdev;
128a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
129a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if(resource == NULL) {
130a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk("No resource\n");
131a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return;
132a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
133a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
134a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	bridge = find_bridge(resource);
135a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if(bridge == NULL) {
136a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk("Can't find bridge\n");
137a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return;
138a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
139a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
140a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Find pci_dev container of dev */
141a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	pdev = container_of(bridge->parent, struct pci_dev, dev);
142a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
143a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	pci_free_consistent(pdev, size, vaddr, dma);
144a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
145a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_free_consistent);
146a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
147a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchsize_t vme_get_size(struct vme_resource *resource)
148a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
149a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	int enabled, retval;
150a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	unsigned long long base, size;
151a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	dma_addr_t buf_base;
152a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_address_t aspace;
153a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_cycle_t cycle;
154a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_width_t dwidth;
155a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
156a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	switch (resource->type) {
157a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_MASTER:
158a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		retval = vme_master_get(resource, &enabled, &base, &size,
159a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			&aspace, &cycle, &dwidth);
160a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
161a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return size;
162a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
163a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_SLAVE:
164a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		retval = vme_slave_get(resource, &enabled, &base, &size,
165a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			&buf_base, &aspace, &cycle);
166a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
167a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return size;
168a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
169a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_DMA:
170a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return 0;
171a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
172a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	default:
173a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_ERR "Unknown resource type\n");
174a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return 0;
175a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
176a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
177a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
178a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_get_size);
179a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
180a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstatic int vme_check_window(vme_address_t aspace, unsigned long long vme_base,
181a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	unsigned long long size)
182a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
183a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	int retval = 0;
184a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
185a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	switch (aspace) {
186a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_A16:
187a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		if (((vme_base + size) > VME_A16_MAX) ||
188a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch				(vme_base > VME_A16_MAX))
189a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			retval = -EFAULT;
190a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
191a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_A24:
192a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		if (((vme_base + size) > VME_A24_MAX) ||
193a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch				(vme_base > VME_A24_MAX))
194a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			retval = -EFAULT;
195a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
196a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_A32:
197a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		if (((vme_base + size) > VME_A32_MAX) ||
198a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch				(vme_base > VME_A32_MAX))
199a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			retval = -EFAULT;
200a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
201a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_A64:
202a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		/*
203a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		 * Any value held in an unsigned long long can be used as the
204a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		 * base
205a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		 */
206a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
207a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_CRCSR:
208a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		if (((vme_base + size) > VME_CRCSR_MAX) ||
209a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch				(vme_base > VME_CRCSR_MAX))
210a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			retval = -EFAULT;
211a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
212a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_USER1:
213a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_USER2:
214a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_USER3:
215a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	case VME_USER4:
216a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		/* User Defined */
217a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
218a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	default:
219a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk("Invalid address space\n");
220a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		retval = -EINVAL;
221a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		break;
222a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
223a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
224a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return retval;
225a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
226a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
227a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
228a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Request a slave image with specific attributes, return some unique
229a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * identifier.
230a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
231a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstruct vme_resource * vme_slave_request(struct device *dev,
232a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_address_t address, vme_cycle_t cycle)
233a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
234a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge;
235a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct list_head *slave_pos = NULL;
236a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_slave_resource *allocated_image = NULL;
237a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_slave_resource *slave_image = NULL;
238a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_resource *resource = NULL;
239a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
240a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	bridge = dev_to_bridge(dev);
241a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge == NULL) {
242a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_ERR "Can't find VME bus\n");
243a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_bus;
244a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
245a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
246a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Loop through slave resources */
247a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	list_for_each(slave_pos, &(bridge->slave_resources)) {
248a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		slave_image = list_entry(slave_pos,
249a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			struct vme_slave_resource, list);
250a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
251a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		if (slave_image == NULL) {
252a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			printk("Registered NULL Slave resource\n");
253a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			continue;
254a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		}
255a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
256a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		/* Find an unlocked and compatible image */
257400822fec46ce69d2ba7692689a1689653f7b847Martyn Welch		mutex_lock(&(slave_image->mtx));
258a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		if(((slave_image->address_attr & address) == address) &&
259a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			((slave_image->cycle_attr & cycle) == cycle) &&
260a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			(slave_image->locked == 0)) {
261a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
262a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			slave_image->locked = 1;
263400822fec46ce69d2ba7692689a1689653f7b847Martyn Welch			mutex_unlock(&(slave_image->mtx));
264a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			allocated_image = slave_image;
265a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			break;
266a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		}
267400822fec46ce69d2ba7692689a1689653f7b847Martyn Welch		mutex_unlock(&(slave_image->mtx));
268a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
269a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
270a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* No free image */
271a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (allocated_image == NULL)
272a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_image;
273a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
274a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	resource = kmalloc(sizeof(struct vme_resource), GFP_KERNEL);
275a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (resource == NULL) {
276a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_WARNING "Unable to allocate resource structure\n");
277a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_alloc;
278a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
279a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	resource->type = VME_SLAVE;
280a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	resource->entry = &(allocated_image->list);
281a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
282a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return resource;
283a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
284a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_alloc:
285a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Unlock image */
286400822fec46ce69d2ba7692689a1689653f7b847Martyn Welch	mutex_lock(&(slave_image->mtx));
287a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	slave_image->locked = 0;
288400822fec46ce69d2ba7692689a1689653f7b847Martyn Welch	mutex_unlock(&(slave_image->mtx));
289a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_image:
290a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_bus:
291a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return NULL;
292a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
293a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_slave_request);
294a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
295a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchint vme_slave_set (struct vme_resource *resource, int enabled,
296a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	unsigned long long vme_base, unsigned long long size,
297a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	dma_addr_t buf_base, vme_address_t aspace, vme_cycle_t cycle)
298a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
299a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge = find_bridge(resource);
300a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_slave_resource *image;
301a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	int retval;
302a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
303a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (resource->type != VME_SLAVE) {
304a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk("Not a slave resource\n");
305a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
306a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
307a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
308a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	image = list_entry(resource->entry, struct vme_slave_resource, list);
309a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
310a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge->slave_set == NULL) {
311a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk("Function not supported\n");
312a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -ENOSYS;
313a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
314a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
315a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if(!(((image->address_attr & aspace) == aspace) &&
316a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		((image->cycle_attr & cycle) == cycle))) {
317a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk("Invalid attributes\n");
318a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
319a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
320a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
321a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	retval = vme_check_window(aspace, vme_base, size);
322a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if(retval)
323a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return retval;
324a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
325a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return bridge->slave_set(image, enabled, vme_base, size, buf_base,
326a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		aspace, cycle);
327a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
328a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_slave_set);
329a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
330a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchint vme_slave_get (struct vme_resource *resource, int *enabled,
331a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	unsigned long long *vme_base, unsigned long long *size,
332a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	dma_addr_t *buf_base, vme_address_t *aspace, vme_cycle_t *cycle)
333a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
334a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge = find_bridge(resource);
335a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_slave_resource *image;
336a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
337a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (resource->type != VME_SLAVE) {
338a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk("Not a slave resource\n");
339a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
340a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
341a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
342a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	image = list_entry(resource->entry, struct vme_slave_resource, list);
343a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
34451a569f757f233bcffbffcdfeeff510916991a55Emilio G. Cota	if (bridge->slave_get == NULL) {
345a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk("vme_slave_get not supported\n");
346a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
347a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
348a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
349a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return bridge->slave_get(image, enabled, vme_base, size, buf_base,
350a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		aspace, cycle);
351a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
352a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_slave_get);
353a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
354a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchvoid vme_slave_free(struct vme_resource *resource)
355a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
356a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_slave_resource *slave_image;
357a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
358a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (resource->type != VME_SLAVE) {
359a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk("Not a slave resource\n");
360a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return;
361a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
362a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
363a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	slave_image = list_entry(resource->entry, struct vme_slave_resource,
364a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		list);
365a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (slave_image == NULL) {
366a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk("Can't find slave resource\n");
367a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return;
368a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
369a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
370a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Unlock image */
371400822fec46ce69d2ba7692689a1689653f7b847Martyn Welch	mutex_lock(&(slave_image->mtx));
372a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (slave_image->locked == 0)
373a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_ERR "Image is already free\n");
374a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
375a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	slave_image->locked = 0;
376400822fec46ce69d2ba7692689a1689653f7b847Martyn Welch	mutex_unlock(&(slave_image->mtx));
377a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
378a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Free up resource memory */
379a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	kfree(resource);
380a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
381a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_slave_free);
382a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
383a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
384a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Request a master image with specific attributes, return some unique
385a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * identifier.
386a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
387a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstruct vme_resource * vme_master_request(struct device *dev,
388a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_address_t address, vme_cycle_t cycle, vme_width_t dwidth)
389a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
390a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge;
391a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct list_head *master_pos = NULL;
392a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_master_resource *allocated_image = NULL;
393a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_master_resource *master_image = NULL;
394a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_resource *resource = NULL;
395a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
396a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	bridge = dev_to_bridge(dev);
397a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge == NULL) {
398a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_ERR "Can't find VME bus\n");
399a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_bus;
400a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
401a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
402a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Loop through master resources */
403a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	list_for_each(master_pos, &(bridge->master_resources)) {
404a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		master_image = list_entry(master_pos,
405a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			struct vme_master_resource, list);
406a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
407a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		if (master_image == NULL) {
408a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			printk(KERN_WARNING "Registered NULL master resource\n");
409a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			continue;
410a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		}
411a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
412a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		/* Find an unlocked and compatible image */
413a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		spin_lock(&(master_image->lock));
414a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		if(((master_image->address_attr & address) == address) &&
415a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			((master_image->cycle_attr & cycle) == cycle) &&
416a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			((master_image->width_attr & dwidth) == dwidth) &&
417a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			(master_image->locked == 0)) {
418a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
419a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			master_image->locked = 1;
420a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			spin_unlock(&(master_image->lock));
421a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			allocated_image = master_image;
422a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			break;
423a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		}
424a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		spin_unlock(&(master_image->lock));
425a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
426a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
427a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Check to see if we found a resource */
428a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (allocated_image == NULL) {
429a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_ERR "Can't find a suitable resource\n");
430a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_image;
431a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
432a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
433a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	resource = kmalloc(sizeof(struct vme_resource), GFP_KERNEL);
434a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (resource == NULL) {
435a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_ERR "Unable to allocate resource structure\n");
436a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_alloc;
437a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
438a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	resource->type = VME_MASTER;
439a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	resource->entry = &(allocated_image->list);
440a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
441a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return resource;
442a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
443a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	kfree(resource);
444a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_alloc:
445a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Unlock image */
446a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	spin_lock(&(master_image->lock));
447a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	master_image->locked = 0;
448a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	spin_unlock(&(master_image->lock));
449a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_image:
450a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_bus:
451a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return NULL;
452a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
453a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_master_request);
454a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
455a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchint vme_master_set (struct vme_resource *resource, int enabled,
456a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	unsigned long long vme_base, unsigned long long size,
457a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_address_t aspace, vme_cycle_t cycle, vme_width_t dwidth)
458a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
459a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge = find_bridge(resource);
460a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_master_resource *image;
461a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	int retval;
462a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
463a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (resource->type != VME_MASTER) {
464a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk("Not a master resource\n");
465a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
466a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
467a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
468a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	image = list_entry(resource->entry, struct vme_master_resource, list);
469a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
470a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge->master_set == NULL) {
471a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk("vme_master_set not supported\n");
472a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
473a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
474a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
475a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if(!(((image->address_attr & aspace) == aspace) &&
476a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		((image->cycle_attr & cycle) == cycle) &&
477a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		((image->width_attr & dwidth) == dwidth))) {
478a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk("Invalid attributes\n");
479a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
480a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
481a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
482a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	retval = vme_check_window(aspace, vme_base, size);
483a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if(retval)
484a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return retval;
485a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
486a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return bridge->master_set(image, enabled, vme_base, size, aspace,
487a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		cycle, dwidth);
488a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
489a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_master_set);
490a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
491a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchint vme_master_get (struct vme_resource *resource, int *enabled,
492a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	unsigned long long *vme_base, unsigned long long *size,
493a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_address_t *aspace, vme_cycle_t *cycle, vme_width_t *dwidth)
494a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
495a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge = find_bridge(resource);
496a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_master_resource *image;
497a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
498a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (resource->type != VME_MASTER) {
499a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk("Not a master resource\n");
500a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
501a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
502a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
503a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	image = list_entry(resource->entry, struct vme_master_resource, list);
504a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
50551a569f757f233bcffbffcdfeeff510916991a55Emilio G. Cota	if (bridge->master_get == NULL) {
506a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk("vme_master_set not supported\n");
507a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
508a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
509a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
510a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return bridge->master_get(image, enabled, vme_base, size, aspace,
511a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		cycle, dwidth);
512a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
513a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_master_get);
514a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
515a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
516a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Read data out of VME space into a buffer.
517a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
518a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchssize_t vme_master_read (struct vme_resource *resource, void *buf, size_t count,
519a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	loff_t offset)
520a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
521a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge = find_bridge(resource);
522a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_master_resource *image;
523a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	size_t length;
524a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
525a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge->master_read == NULL) {
526a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk("Reading from resource not supported\n");
527a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
528a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
529a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
530a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (resource->type != VME_MASTER) {
531a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk("Not a master resource\n");
532a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
533a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
534a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
535a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	image = list_entry(resource->entry, struct vme_master_resource, list);
536a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
537a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	length = vme_get_size(resource);
538a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
539a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (offset > length) {
540a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk("Invalid Offset\n");
541a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EFAULT;
542a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
543a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
544a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if ((offset + count) > length)
545a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		count = length - offset;
546a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
547a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return bridge->master_read(image, buf, count, offset);
548a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
549a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
550a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_master_read);
551a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
552a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
553a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Write data out to VME space from a buffer.
554a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
555a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchssize_t vme_master_write (struct vme_resource *resource, void *buf,
556a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	size_t count, loff_t offset)
557a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
558a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge = find_bridge(resource);
559a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_master_resource *image;
560a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	size_t length;
561a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
562a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge->master_write == NULL) {
563a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk("Writing to resource not supported\n");
564a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
565a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
566a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
567a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (resource->type != VME_MASTER) {
568a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk("Not a master resource\n");
569a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
570a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
571a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
572a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	image = list_entry(resource->entry, struct vme_master_resource, list);
573a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
574a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	length = vme_get_size(resource);
575a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
576a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (offset > length) {
577a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk("Invalid Offset\n");
578a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EFAULT;
579a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
580a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
581a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if ((offset + count) > length)
582a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		count = length - offset;
583a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
584a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return bridge->master_write(image, buf, count, offset);
585a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
586a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_master_write);
587a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
588a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
589a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Perform RMW cycle to provided location.
590a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
591a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchunsigned int vme_master_rmw (struct vme_resource *resource, unsigned int mask,
592a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	unsigned int compare, unsigned int swap, loff_t offset)
593a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
594a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge = find_bridge(resource);
595a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_master_resource *image;
596a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
597a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge->master_rmw == NULL) {
598a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk("Writing to resource not supported\n");
599a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
600a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
601a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
602a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (resource->type != VME_MASTER) {
603a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk("Not a master resource\n");
604a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
605a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
606a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
607a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	image = list_entry(resource->entry, struct vme_master_resource, list);
608a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
609a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return bridge->master_rmw(image, mask, compare, swap, offset);
610a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
611a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_master_rmw);
612a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
613a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchvoid vme_master_free(struct vme_resource *resource)
614a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
615a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_master_resource *master_image;
616a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
617a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (resource->type != VME_MASTER) {
618a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk("Not a master resource\n");
619a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return;
620a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
621a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
622a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	master_image = list_entry(resource->entry, struct vme_master_resource,
623a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		list);
624a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (master_image == NULL) {
625a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk("Can't find master resource\n");
626a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return;
627a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
628a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
629a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Unlock image */
630a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	spin_lock(&(master_image->lock));
631a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (master_image->locked == 0)
632a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_ERR "Image is already free\n");
633a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
634a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	master_image->locked = 0;
635a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	spin_unlock(&(master_image->lock));
636a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
637a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Free up resource memory */
638a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	kfree(resource);
639a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
640a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_master_free);
641a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
642a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
643a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Request a DMA controller with specific attributes, return some unique
644a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * identifier.
645a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
64658e507987b285f3df99f839c79da3985555ac220Martyn Welchstruct vme_resource *vme_dma_request(struct device *dev)
647a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
648a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge;
649a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct list_head *dma_pos = NULL;
650a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_dma_resource *allocated_ctrlr = NULL;
651a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_dma_resource *dma_ctrlr = NULL;
652a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_resource *resource = NULL;
653a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
654a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* XXX Not checking resource attributes */
655a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	printk(KERN_ERR "No VME resource Attribute tests done\n");
656a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
657a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	bridge = dev_to_bridge(dev);
658a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge == NULL) {
659a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_ERR "Can't find VME bus\n");
660a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_bus;
661a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
662a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
663a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Loop through DMA resources */
664a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	list_for_each(dma_pos, &(bridge->dma_resources)) {
665a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		dma_ctrlr = list_entry(dma_pos,
666a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			struct vme_dma_resource, list);
667a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
668a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		if (dma_ctrlr == NULL) {
669a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			printk("Registered NULL DMA resource\n");
670a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			continue;
671a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		}
672a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
673a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		/* Find an unlocked controller */
674400822fec46ce69d2ba7692689a1689653f7b847Martyn Welch		mutex_lock(&(dma_ctrlr->mtx));
675a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		if(dma_ctrlr->locked == 0) {
676a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			dma_ctrlr->locked = 1;
677400822fec46ce69d2ba7692689a1689653f7b847Martyn Welch			mutex_unlock(&(dma_ctrlr->mtx));
678a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			allocated_ctrlr = dma_ctrlr;
679a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			break;
680a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		}
681400822fec46ce69d2ba7692689a1689653f7b847Martyn Welch		mutex_unlock(&(dma_ctrlr->mtx));
682a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
683a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
684a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Check to see if we found a resource */
685a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (allocated_ctrlr == NULL)
686a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_ctrlr;
687a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
688a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	resource = kmalloc(sizeof(struct vme_resource), GFP_KERNEL);
689a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (resource == NULL) {
690a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_WARNING "Unable to allocate resource structure\n");
691a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_alloc;
692a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
693a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	resource->type = VME_DMA;
694a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	resource->entry = &(allocated_ctrlr->list);
695a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
696a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return resource;
697a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
698a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_alloc:
699a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Unlock image */
700400822fec46ce69d2ba7692689a1689653f7b847Martyn Welch	mutex_lock(&(dma_ctrlr->mtx));
701a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	dma_ctrlr->locked = 0;
702400822fec46ce69d2ba7692689a1689653f7b847Martyn Welch	mutex_unlock(&(dma_ctrlr->mtx));
703a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_ctrlr:
704a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_bus:
705a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return NULL;
706a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
70758e507987b285f3df99f839c79da3985555ac220Martyn WelchEXPORT_SYMBOL(vme_dma_request);
708a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
709a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
710a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Start new list
711a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
712a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstruct vme_dma_list *vme_new_dma_list(struct vme_resource *resource)
713a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
714a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_dma_resource *ctrlr;
715a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_dma_list *dma_list;
716a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
717a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (resource->type != VME_DMA) {
718a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk("Not a DMA resource\n");
719a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return NULL;
720a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
721a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
722a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	ctrlr = list_entry(resource->entry, struct vme_dma_resource, list);
723a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
724a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	dma_list = (struct vme_dma_list *)kmalloc(
725a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		sizeof(struct vme_dma_list), GFP_KERNEL);
726a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if(dma_list == NULL) {
727a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk("Unable to allocate memory for new dma list\n");
728a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return NULL;
729a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
730a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	INIT_LIST_HEAD(&(dma_list->entries));
731a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	dma_list->parent = ctrlr;
732400822fec46ce69d2ba7692689a1689653f7b847Martyn Welch	mutex_init(&(dma_list->mtx));
733a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
734a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return dma_list;
735a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
736a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_new_dma_list);
737a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
738a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
739a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Create "Pattern" type attributes
740a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
741a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstruct vme_dma_attr *vme_dma_pattern_attribute(u32 pattern,
742a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_pattern_t type)
743a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
744a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_dma_attr *attributes;
745a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_dma_pattern *pattern_attr;
746a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
747a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	attributes = (struct vme_dma_attr *)kmalloc(
748a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		sizeof(struct vme_dma_attr), GFP_KERNEL);
749a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if(attributes == NULL) {
750a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk("Unable to allocate memory for attributes structure\n");
751a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_attr;
752a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
753a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
754a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	pattern_attr = (struct vme_dma_pattern *)kmalloc(
755a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		sizeof(struct vme_dma_pattern), GFP_KERNEL);
756a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if(pattern_attr == NULL) {
757a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk("Unable to allocate memory for pattern attributes\n");
758a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_pat;
759a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
760a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
761a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	attributes->type = VME_DMA_PATTERN;
762a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	attributes->private = (void *)pattern_attr;
763a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
764a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	pattern_attr->pattern = pattern;
765a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	pattern_attr->type = type;
766a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
767a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return attributes;
768a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
769a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	kfree(pattern_attr);
770a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_pat:
771a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	kfree(attributes);
772a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_attr:
773a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return NULL;
774a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
775a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_dma_pattern_attribute);
776a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
777a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
778a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Create "PCI" type attributes
779a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
780a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstruct vme_dma_attr *vme_dma_pci_attribute(dma_addr_t address)
781a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
782a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_dma_attr *attributes;
783a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_dma_pci *pci_attr;
784a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
785a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* XXX Run some sanity checks here */
786a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
787a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	attributes = (struct vme_dma_attr *)kmalloc(
788a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		sizeof(struct vme_dma_attr), GFP_KERNEL);
789a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if(attributes == NULL) {
790a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk("Unable to allocate memory for attributes structure\n");
791a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_attr;
792a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
793a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
794a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	pci_attr = (struct vme_dma_pci *)kmalloc(sizeof(struct vme_dma_pci),
795a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		GFP_KERNEL);
796a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if(pci_attr == NULL) {
797a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk("Unable to allocate memory for pci attributes\n");
798a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_pci;
799a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
800a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
801a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
802a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
803a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	attributes->type = VME_DMA_PCI;
804a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	attributes->private = (void *)pci_attr;
805a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
806a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	pci_attr->address = address;
807a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
808a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return attributes;
809a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
810a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	kfree(pci_attr);
811a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_pci:
812a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	kfree(attributes);
813a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_attr:
814a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return NULL;
815a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
816a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_dma_pci_attribute);
817a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
818a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
819a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Create "VME" type attributes
820a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
821a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstruct vme_dma_attr *vme_dma_vme_attribute(unsigned long long address,
822a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_address_t aspace, vme_cycle_t cycle, vme_width_t dwidth)
823a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
824a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_dma_attr *attributes;
825a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_dma_vme *vme_attr;
826a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
827a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* XXX Run some sanity checks here */
828a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
829a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	attributes = (struct vme_dma_attr *)kmalloc(
830a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		sizeof(struct vme_dma_attr), GFP_KERNEL);
831a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if(attributes == NULL) {
832a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk("Unable to allocate memory for attributes structure\n");
833a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_attr;
834a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
835a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
836a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_attr = (struct vme_dma_vme *)kmalloc(sizeof(struct vme_dma_vme),
837a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		GFP_KERNEL);
838a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if(vme_attr == NULL) {
839a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk("Unable to allocate memory for vme attributes\n");
840a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_vme;
841a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
842a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
843a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	attributes->type = VME_DMA_VME;
844a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	attributes->private = (void *)vme_attr;
845a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
846a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_attr->address = address;
847a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_attr->aspace = aspace;
848a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_attr->cycle = cycle;
849a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_attr->dwidth = dwidth;
850a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
851a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return attributes;
852a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
853a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	kfree(vme_attr);
854a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_vme:
855a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	kfree(attributes);
856a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_attr:
857a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return NULL;
858a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
859a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_dma_vme_attribute);
860a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
861a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/*
862a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch * Free attribute
863a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch */
864a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchvoid vme_dma_free_attribute(struct vme_dma_attr *attributes)
865a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
866a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	kfree(attributes->private);
867a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	kfree(attributes);
868a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
869a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_dma_free_attribute);
870a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
871a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchint vme_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src,
872a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_dma_attr *dest, size_t count)
873a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
874a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge = list->parent->parent;
875a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	int retval;
876a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
877a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge->dma_list_add == NULL) {
878a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk("Link List DMA generation not supported\n");
879a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
880a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
881a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
882400822fec46ce69d2ba7692689a1689653f7b847Martyn Welch	if (mutex_trylock(&(list->mtx))) {
883a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk("Link List already submitted\n");
884a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
885a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
886a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
887a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	retval = bridge->dma_list_add(list, src, dest, count);
888a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
889400822fec46ce69d2ba7692689a1689653f7b847Martyn Welch	mutex_unlock(&(list->mtx));
890a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
891a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return retval;
892a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
893a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_dma_list_add);
894a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
895a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchint vme_dma_list_exec(struct vme_dma_list *list)
896a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
897a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge = list->parent->parent;
898a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	int retval;
899a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
900a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge->dma_list_exec == NULL) {
901a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk("Link List DMA execution not supported\n");
902a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
903a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
904a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
905400822fec46ce69d2ba7692689a1689653f7b847Martyn Welch	mutex_lock(&(list->mtx));
906a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
907a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	retval = bridge->dma_list_exec(list);
908a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
909400822fec46ce69d2ba7692689a1689653f7b847Martyn Welch	mutex_unlock(&(list->mtx));
910a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
911a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return retval;
912a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
913a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_dma_list_exec);
914a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
915a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchint vme_dma_list_free(struct vme_dma_list *list)
916a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
917a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge = list->parent->parent;
918a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	int retval;
919a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
920a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge->dma_list_empty == NULL) {
921a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk("Emptying of Link Lists not supported\n");
922a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
923a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
924a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
925400822fec46ce69d2ba7692689a1689653f7b847Martyn Welch	if (mutex_trylock(&(list->mtx))) {
926a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk("Link List in use\n");
927a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
928a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
929a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
930a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/*
931a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	 * Empty out all of the entries from the dma list. We need to go to the
932a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	 * low level driver as dma entries are driver specific.
933a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	 */
934a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	retval = bridge->dma_list_empty(list);
935a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (retval) {
936a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk("Unable to empty link-list entries\n");
937400822fec46ce69d2ba7692689a1689653f7b847Martyn Welch		mutex_unlock(&(list->mtx));
938a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return retval;
939a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
940400822fec46ce69d2ba7692689a1689653f7b847Martyn Welch	mutex_unlock(&(list->mtx));
941a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	kfree(list);
942a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
943a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return retval;
944a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
945a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_dma_list_free);
946a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
947a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchint vme_dma_free(struct vme_resource *resource)
948a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
949a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_dma_resource *ctrlr;
950a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
951a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (resource->type != VME_DMA) {
952a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk("Not a DMA resource\n");
953a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
954a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
955a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
956a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	ctrlr = list_entry(resource->entry, struct vme_dma_resource, list);
957a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
958400822fec46ce69d2ba7692689a1689653f7b847Martyn Welch	if (mutex_trylock(&(ctrlr->mtx))) {
959a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk("Resource busy, can't free\n");
960a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EBUSY;
961a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
962a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
963a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (!(list_empty(&(ctrlr->pending)) && list_empty(&(ctrlr->running)))) {
964a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk("Resource still processing transfers\n");
965400822fec46ce69d2ba7692689a1689653f7b847Martyn Welch		mutex_unlock(&(ctrlr->mtx));
966a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EBUSY;
967a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
968a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
969a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	ctrlr->locked = 0;
970a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
971400822fec46ce69d2ba7692689a1689653f7b847Martyn Welch	mutex_unlock(&(ctrlr->mtx));
972a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
973a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return 0;
974a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
975a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_dma_free);
976a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
977c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welchvoid vme_irq_handler(struct vme_bridge *bridge, int level, int statid)
978c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch{
979c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	void (*call)(int, int, void *);
980c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	void *priv_data;
981c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch
982c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	call = bridge->irq[level - 1].callback[statid].func;
983c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	priv_data = bridge->irq[level - 1].callback[statid].priv_data;
984c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch
985c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	if (call != NULL)
986c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch		call(level, statid, priv_data);
987c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	else
988c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch		printk(KERN_WARNING "Spurilous VME interrupt, level:%x, "
989c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch			"vector:%x\n", level, statid);
990c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch}
991c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn WelchEXPORT_SYMBOL(vme_irq_handler);
992c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch
993c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welchint vme_irq_request(struct device *dev, int level, int statid,
994a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	void (*callback)(int level, int vector, void *priv_data),
995a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	void *priv_data)
996a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
997a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge;
998a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
999a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	bridge = dev_to_bridge(dev);
1000a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge == NULL) {
1001a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_ERR "Can't find VME bus\n");
1002a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
1003a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1004a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1005a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if((level < 1) || (level > 7)) {
1006c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch		printk(KERN_ERR "Invalid interrupt level\n");
1007a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
1008a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1009a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1010c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	if (bridge->irq_set == NULL) {
1011c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch		printk(KERN_ERR "Configuring interrupts not supported\n");
1012a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
1013a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1014a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1015c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	mutex_lock(&(bridge->irq_mtx));
1016c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch
1017c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	if (bridge->irq[level - 1].callback[statid].func) {
1018c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch		mutex_unlock(&(bridge->irq_mtx));
1019c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch		printk(KERN_WARNING "VME Interrupt already taken\n");
1020c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch		return -EBUSY;
1021c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	}
1022c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch
1023c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	bridge->irq[level - 1].count++;
1024c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	bridge->irq[level - 1].callback[statid].priv_data = priv_data;
1025c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	bridge->irq[level - 1].callback[statid].func = callback;
1026c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch
1027c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	/* Enable IRQ level */
1028c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	bridge->irq_set(level, 1, 1);
1029c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch
1030c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	mutex_unlock(&(bridge->irq_mtx));
1031c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch
1032c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	return 0;
1033a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1034c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn WelchEXPORT_SYMBOL(vme_irq_request);
1035a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1036c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welchvoid vme_irq_free(struct device *dev, int level, int statid)
1037a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1038a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge;
1039a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1040a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	bridge = dev_to_bridge(dev);
1041a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge == NULL) {
1042a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_ERR "Can't find VME bus\n");
1043a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return;
1044a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1045a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1046a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if((level < 1) || (level > 7)) {
1047c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch		printk(KERN_ERR "Invalid interrupt level\n");
1048a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return;
1049a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1050a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1051c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	if (bridge->irq_set == NULL) {
1052c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch		printk(KERN_ERR "Configuring interrupts not supported\n");
1053a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return;
1054a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1055a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1056c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	mutex_lock(&(bridge->irq_mtx));
1057c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch
1058c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	bridge->irq[level - 1].count--;
1059c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch
1060c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	/* Disable IRQ level if no more interrupts attached at this level*/
1061c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	if (bridge->irq[level - 1].count == 0)
1062c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch		bridge->irq_set(level, 0, 1);
1063c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch
1064c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	bridge->irq[level - 1].callback[statid].func = NULL;
1065c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	bridge->irq[level - 1].callback[statid].priv_data = NULL;
1066c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch
1067c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	mutex_unlock(&(bridge->irq_mtx));
1068a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1069c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn WelchEXPORT_SYMBOL(vme_irq_free);
1070a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1071c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welchint vme_irq_generate(struct device *dev, int level, int statid)
1072a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1073a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge;
1074a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1075a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	bridge = dev_to_bridge(dev);
1076a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge == NULL) {
1077a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_ERR "Can't find VME bus\n");
1078a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
1079a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1080a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1081a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if((level < 1) || (level > 7)) {
1082a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_WARNING "Invalid interrupt level\n");
1083a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
1084a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1085a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1086c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	if (bridge->irq_generate == NULL) {
1087a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk("Interrupt generation not supported\n");
1088a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
1089a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1090a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1091c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn Welch	return bridge->irq_generate(level, statid);
1092a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1093c813f592a5e65cfd9321f51c95a6977e9518dde6Martyn WelchEXPORT_SYMBOL(vme_irq_generate);
1094a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
109542fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch/*
109642fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch * Request the location monitor, return resource or NULL
109742fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch */
109842fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welchstruct vme_resource *vme_lm_request(struct device *dev)
1099a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1100a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge;
110142fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	struct list_head *lm_pos = NULL;
110242fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	struct vme_lm_resource *allocated_lm = NULL;
110342fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	struct vme_lm_resource *lm = NULL;
110442fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	struct vme_resource *resource = NULL;
1105a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1106a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	bridge = dev_to_bridge(dev);
1107a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge == NULL) {
1108a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_ERR "Can't find VME bus\n");
110942fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		goto err_bus;
111042fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	}
111142fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
111242fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	/* Loop through DMA resources */
111342fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	list_for_each(lm_pos, &(bridge->lm_resources)) {
111442fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		lm = list_entry(lm_pos,
111542fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch			struct vme_lm_resource, list);
111642fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
111742fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		if (lm == NULL) {
111842fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch			printk(KERN_ERR "Registered NULL Location Monitor "
111942fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch				"resource\n");
112042fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch			continue;
112142fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		}
112242fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
112342fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		/* Find an unlocked controller */
112442fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		mutex_lock(&(lm->mtx));
112542fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		if (lm->locked == 0) {
112642fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch			lm->locked = 1;
112742fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch			mutex_unlock(&(lm->mtx));
112842fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch			allocated_lm = lm;
112942fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch			break;
113042fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		}
113142fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		mutex_unlock(&(lm->mtx));
113242fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	}
113342fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
113442fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	/* Check to see if we found a resource */
113542fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	if (allocated_lm == NULL)
113642fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		goto err_lm;
113742fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
113842fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	resource = kmalloc(sizeof(struct vme_resource), GFP_KERNEL);
113942fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	if (resource == NULL) {
114042fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		printk(KERN_ERR "Unable to allocate resource structure\n");
114142fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		goto err_alloc;
114242fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	}
114342fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	resource->type = VME_LM;
114442fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	resource->entry = &(allocated_lm->list);
114542fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
114642fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	return resource;
114742fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
114842fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welcherr_alloc:
114942fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	/* Unlock image */
115042fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	mutex_lock(&(lm->mtx));
115142fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	lm->locked = 0;
115242fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	mutex_unlock(&(lm->mtx));
115342fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welcherr_lm:
115442fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welcherr_bus:
115542fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	return NULL;
115642fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch}
115742fb503122d8cd428b5b1078bd473847ca2b206cMartyn WelchEXPORT_SYMBOL(vme_lm_request);
115842fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
115942fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welchint vme_lm_count(struct vme_resource *resource)
116042fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch{
116142fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	struct vme_lm_resource *lm;
116242fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
116342fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	if (resource->type != VME_LM) {
116442fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		printk(KERN_ERR "Not a Location Monitor resource\n");
116542fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		return -EINVAL;
116642fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	}
116742fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
116842fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	lm = list_entry(resource->entry, struct vme_lm_resource, list);
116942fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
117042fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	return lm->monitors;
117142fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch}
117242fb503122d8cd428b5b1078bd473847ca2b206cMartyn WelchEXPORT_SYMBOL(vme_lm_count);
117342fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
117442fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welchint vme_lm_set(struct vme_resource *resource, unsigned long long lm_base,
117542fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	vme_address_t aspace, vme_cycle_t cycle)
117642fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch{
117742fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	struct vme_bridge *bridge = find_bridge(resource);
117842fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	struct vme_lm_resource *lm;
117942fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
118042fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	if (resource->type != VME_LM) {
118142fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		printk(KERN_ERR "Not a Location Monitor resource\n");
1182a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
1183a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1184a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
118542fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	lm = list_entry(resource->entry, struct vme_lm_resource, list);
118642fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
1187a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge->lm_set == NULL) {
118842fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		printk(KERN_ERR "vme_lm_set not supported\n");
1189a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
1190a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1191a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
119242fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	/* XXX Check parameters */
119342fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
11948be9226c8f686c6dd2bae0a7ed4f5795e89d32d8Martyn Welch	return bridge->lm_set(lm, lm_base, aspace, cycle);
1195a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1196a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_lm_set);
1197a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
119842fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welchint vme_lm_get(struct vme_resource *resource, unsigned long long *lm_base,
119942fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	vme_address_t *aspace, vme_cycle_t *cycle)
1200a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
120142fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	struct vme_bridge *bridge = find_bridge(resource);
120242fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	struct vme_lm_resource *lm;
1203a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
120442fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	if (resource->type != VME_LM) {
120542fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		printk(KERN_ERR "Not a Location Monitor resource\n");
1206a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
1207a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1208a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
120942fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	lm = list_entry(resource->entry, struct vme_lm_resource, list);
121042fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
1211a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge->lm_get == NULL) {
121242fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		printk(KERN_ERR "vme_lm_get not supported\n");
1213a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
1214a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1215a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
121642fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	return bridge->lm_get(lm, lm_base, aspace, cycle);
1217a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1218a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_lm_get);
1219a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
122042fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welchint vme_lm_attach(struct vme_resource *resource, int monitor,
122142fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	void (*callback)(int))
1222a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
122342fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	struct vme_bridge *bridge = find_bridge(resource);
122442fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	struct vme_lm_resource *lm;
1225a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
122642fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	if (resource->type != VME_LM) {
122742fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		printk(KERN_ERR "Not a Location Monitor resource\n");
1228a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
1229a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1230a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
123142fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	lm = list_entry(resource->entry, struct vme_lm_resource, list);
123242fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
1233a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge->lm_attach == NULL) {
123442fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		printk(KERN_ERR "vme_lm_attach not supported\n");
1235a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
1236a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1237a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
123842fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	return bridge->lm_attach(lm, monitor, callback);
1239a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1240a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_lm_attach);
1241a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
124242fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welchint vme_lm_detach(struct vme_resource *resource, int monitor)
1243a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
124442fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	struct vme_bridge *bridge = find_bridge(resource);
124542fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	struct vme_lm_resource *lm;
1246a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
124742fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	if (resource->type != VME_LM) {
124842fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		printk(KERN_ERR "Not a Location Monitor resource\n");
1249a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
1250a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1251a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
125242fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	lm = list_entry(resource->entry, struct vme_lm_resource, list);
125342fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
1254a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge->lm_detach == NULL) {
125542fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		printk(KERN_ERR "vme_lm_detach not supported\n");
1256a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
1257a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1258a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
125942fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	return bridge->lm_detach(lm, monitor);
1260a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1261a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_lm_detach);
1262a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
126342fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welchvoid vme_lm_free(struct vme_resource *resource)
126442fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch{
126542fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	struct vme_lm_resource *lm;
126642fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
126742fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	if (resource->type != VME_LM) {
126842fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		printk(KERN_ERR "Not a Location Monitor resource\n");
126942fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch		return;
127042fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	}
127142fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
127242fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	lm = list_entry(resource->entry, struct vme_lm_resource, list);
127342fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
12748be9226c8f686c6dd2bae0a7ed4f5795e89d32d8Martyn Welch	mutex_lock(&(lm->mtx));
127542fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
12768be9226c8f686c6dd2bae0a7ed4f5795e89d32d8Martyn Welch	/* XXX
12778be9226c8f686c6dd2bae0a7ed4f5795e89d32d8Martyn Welch	 * Check to see that there aren't any callbacks still attached, if
12788be9226c8f686c6dd2bae0a7ed4f5795e89d32d8Martyn Welch	 * there are we should probably be detaching them!
12798be9226c8f686c6dd2bae0a7ed4f5795e89d32d8Martyn Welch	 */
128042fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
128142fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	lm->locked = 0;
128242fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
128342fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch	mutex_unlock(&(lm->mtx));
12848be9226c8f686c6dd2bae0a7ed4f5795e89d32d8Martyn Welch
12858be9226c8f686c6dd2bae0a7ed4f5795e89d32d8Martyn Welch	kfree(resource);
128642fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch}
128742fb503122d8cd428b5b1078bd473847ca2b206cMartyn WelchEXPORT_SYMBOL(vme_lm_free);
128842fb503122d8cd428b5b1078bd473847ca2b206cMartyn Welch
1289a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchint vme_slot_get(struct device *bus)
1290a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1291a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge;
1292a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1293a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	bridge = dev_to_bridge(bus);
1294a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge == NULL) {
1295a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk(KERN_ERR "Can't find VME bus\n");
1296a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
1297a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1298a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1299a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (bridge->slot_get == NULL) {
1300a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk("vme_slot_get not supported\n");
1301a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		return -EINVAL;
1302a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1303a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1304a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return bridge->slot_get();
1305a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1306a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_slot_get);
1307a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1308a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1309a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/* - Bridge Registration --------------------------------------------------- */
1310a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1311a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstatic int vme_alloc_bus_num(void)
1312a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1313a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	int i;
1314a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1315400822fec46ce69d2ba7692689a1689653f7b847Martyn Welch	mutex_lock(&vme_bus_num_mtx);
1316a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	for (i = 0; i < sizeof(vme_bus_numbers) * 8; i++) {
1317a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		if (((vme_bus_numbers >> i) & 0x1) == 0) {
1318a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			vme_bus_numbers |= (0x1 << i);
1319a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			break;
1320a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		}
1321a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1322400822fec46ce69d2ba7692689a1689653f7b847Martyn Welch	mutex_unlock(&vme_bus_num_mtx);
1323a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1324a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return i;
1325a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1326a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1327a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstatic void vme_free_bus_num(int bus)
1328a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1329400822fec46ce69d2ba7692689a1689653f7b847Martyn Welch	mutex_lock(&vme_bus_num_mtx);
1330a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_bus_numbers |= ~(0x1 << bus);
1331400822fec46ce69d2ba7692689a1689653f7b847Martyn Welch	mutex_unlock(&vme_bus_num_mtx);
1332a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1333a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1334a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchint vme_register_bridge (struct vme_bridge *bridge)
1335a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1336a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct device *dev;
1337a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	int retval;
1338a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	int i;
1339a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1340a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	bridge->num = vme_alloc_bus_num();
1341a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1342a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* This creates 32 vme "slot" devices. This equates to a slot for each
1343a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	 * ID available in a system conforming to the ANSI/VITA 1-1994
1344a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	 * specification.
1345a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	 */
1346a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	for (i = 0; i < VME_SLOTS_MAX; i++) {
1347a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		dev = &(bridge->dev[i]);
1348a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		memset(dev, 0, sizeof(struct device));
1349a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1350a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		dev->parent = bridge->parent;
1351a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		dev->bus = &(vme_bus_type);
1352a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		/*
1353a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		 * We save a pointer to the bridge in platform_data so that we
1354a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		 * can get to it later. We keep driver_data for use by the
1355a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		 * driver that binds against the slot
1356a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		 */
1357a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		dev->platform_data = bridge;
1358a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		dev_set_name(dev, "vme-%x.%x", bridge->num, i + 1);
1359a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1360a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		retval = device_register(dev);
1361a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		if(retval)
1362a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			goto err_reg;
1363a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1364a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1365a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return retval;
1366a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1367a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	i = VME_SLOTS_MAX;
1368a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_reg:
1369a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	while (i > -1) {
1370a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		dev = &(bridge->dev[i]);
1371a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		device_unregister(dev);
1372a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1373a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_free_bus_num(bridge->num);
1374a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return retval;
1375a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1376a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_register_bridge);
1377a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1378a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchvoid vme_unregister_bridge (struct vme_bridge *bridge)
1379a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1380a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	int i;
1381a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct device *dev;
1382a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1383a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1384a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	for (i = 0; i < VME_SLOTS_MAX; i++) {
1385a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		dev = &(bridge->dev[i]);
1386a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		device_unregister(dev);
1387a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1388a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	vme_free_bus_num(bridge->num);
1389a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1390a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_unregister_bridge);
1391a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1392a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1393a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/* - Driver Registration --------------------------------------------------- */
1394a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1395a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchint vme_register_driver (struct vme_driver *drv)
1396a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1397a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	drv->driver.name = drv->name;
1398a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	drv->driver.bus = &vme_bus_type;
1399a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1400a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return driver_register(&drv->driver);
1401a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1402a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_register_driver);
1403a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1404a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchvoid vme_unregister_driver (struct vme_driver *drv)
1405a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1406a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	driver_unregister(&drv->driver);
1407a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1408a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_unregister_driver);
1409a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1410a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch/* - Bus Registration ------------------------------------------------------ */
1411a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1412a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchint vme_calc_slot(struct device *dev)
1413a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1414a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge;
1415a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	int num;
1416a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1417a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	bridge = dev_to_bridge(dev);
1418a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1419a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	/* Determine slot number */
1420a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	num = 0;
1421a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	while(num < VME_SLOTS_MAX) {
1422a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		if(&(bridge->dev[num]) == dev) {
1423a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch			break;
1424a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		}
1425a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		num++;
1426a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1427a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (num == VME_SLOTS_MAX) {
1428a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		dev_err(dev, "Failed to identify slot\n");
1429a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		num = 0;
1430a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_dev;
1431a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1432a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	num++;
1433a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1434a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_dev:
1435a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return num;
1436a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1437a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1438a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstatic struct vme_driver *dev_to_vme_driver(struct device *dev)
1439a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1440a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if(dev->driver == NULL)
1441a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		printk("Bugger dev->driver is NULL\n");
1442a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1443a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return container_of(dev->driver, struct vme_driver, driver);
1444a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1445a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1446a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstatic int vme_bus_match(struct device *dev, struct device_driver *drv)
1447a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1448a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge;
1449a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_driver *driver;
1450a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	int i, num;
1451a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1452a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	bridge = dev_to_bridge(dev);
1453a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	driver = container_of(drv, struct vme_driver, driver);
1454a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1455a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	num = vme_calc_slot(dev);
1456a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (!num)
1457a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_dev;
1458a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1459a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if (driver->bind_table == NULL) {
1460a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		dev_err(dev, "Bind table NULL\n");
1461a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		goto err_table;
1462a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1463a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1464a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	i = 0;
1465a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	while((driver->bind_table[i].bus != 0) ||
1466a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		(driver->bind_table[i].slot != 0)) {
1467a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1468a37b0dad8b3d278fa64482ccd2381c947f432bf7Martyn Welch		if (bridge->num == driver->bind_table[i].bus) {
1469a37b0dad8b3d278fa64482ccd2381c947f432bf7Martyn Welch			if (num == driver->bind_table[i].slot)
1470a37b0dad8b3d278fa64482ccd2381c947f432bf7Martyn Welch				return 1;
1471a37b0dad8b3d278fa64482ccd2381c947f432bf7Martyn Welch
1472a37b0dad8b3d278fa64482ccd2381c947f432bf7Martyn Welch			if (driver->bind_table[i].slot == VME_SLOT_ALL)
1473a37b0dad8b3d278fa64482ccd2381c947f432bf7Martyn Welch				return 1;
1474a37b0dad8b3d278fa64482ccd2381c947f432bf7Martyn Welch
1475a37b0dad8b3d278fa64482ccd2381c947f432bf7Martyn Welch			if ((driver->bind_table[i].slot == VME_SLOT_CURRENT) &&
1476a37b0dad8b3d278fa64482ccd2381c947f432bf7Martyn Welch				(num == vme_slot_get(dev)))
1477a37b0dad8b3d278fa64482ccd2381c947f432bf7Martyn Welch				return 1;
1478a37b0dad8b3d278fa64482ccd2381c947f432bf7Martyn Welch		}
1479a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		i++;
1480a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1481a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1482a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_dev:
1483a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welcherr_table:
1484a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return 0;
1485a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1486a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1487a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstatic int vme_bus_probe(struct device *dev)
1488a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1489a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge;
1490a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_driver *driver;
1491a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	int retval = -ENODEV;
1492a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1493a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	driver = dev_to_vme_driver(dev);
1494a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	bridge = dev_to_bridge(dev);
1495a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1496a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if(driver->probe != NULL) {
1497a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		retval = driver->probe(dev, bridge->num, vme_calc_slot(dev));
1498a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1499a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1500a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return retval;
1501a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1502a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1503a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstatic int vme_bus_remove(struct device *dev)
1504a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1505a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_bridge *bridge;
1506a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	struct vme_driver *driver;
1507a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	int retval = -ENODEV;
1508a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1509a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	driver = dev_to_vme_driver(dev);
1510a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	bridge = dev_to_bridge(dev);
1511a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1512a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	if(driver->remove != NULL) {
1513a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch		retval = driver->remove(dev, bridge->num, vme_calc_slot(dev));
1514a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	}
1515a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1516a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return retval;
1517a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1518a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1519a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstruct bus_type vme_bus_type = {
1520a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	.name = "vme",
1521a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	.match = vme_bus_match,
1522a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	.probe = vme_bus_probe,
1523a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	.remove = vme_bus_remove,
1524a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch};
1525a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchEXPORT_SYMBOL(vme_bus_type);
1526a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1527a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstatic int __init vme_init (void)
1528a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1529a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	return bus_register(&vme_bus_type);
1530a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1531a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1532a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchstatic void __exit vme_exit (void)
1533a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch{
1534a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch	bus_unregister(&vme_bus_type);
1535a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch}
1536a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1537a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchMODULE_DESCRIPTION("VME bridge driver framework");
1538a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchMODULE_AUTHOR("Martyn Welch <martyn.welch@gefanuc.com");
1539a17a75e2666f7175baac838bc4b6d11324dca3efMartyn WelchMODULE_LICENSE("GPL");
1540a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welch
1541a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchmodule_init(vme_init);
1542a17a75e2666f7175baac838bc4b6d11324dca3efMartyn Welchmodule_exit(vme_exit);
1543