aboutsummaryrefslogtreecommitdiff
path: root/drivers/staging/vme/vme.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/vme/vme.c')
-rw-r--r--drivers/staging/vme/vme.c170
1 files changed, 144 insertions, 26 deletions
diff --git a/drivers/staging/vme/vme.c b/drivers/staging/vme/vme.c
index 07b254a6535..477a1adfd0e 100644
--- a/drivers/staging/vme/vme.c
+++ b/drivers/staging/vme/vme.c
@@ -69,6 +69,10 @@ static struct vme_bridge *find_bridge(struct vme_resource *resource)
return list_entry(resource->entry, struct vme_dma_resource,
list)->parent;
break;
+ case VME_LM:
+ return list_entry(resource->entry, struct vme_lm_resource,
+ list)->parent;
+ break;
default:
printk(KERN_ERR "Unknown resource type\n");
return NULL;
@@ -1045,84 +1049,198 @@ int vme_generate_irq(struct device *dev, int level, int statid)
}
EXPORT_SYMBOL(vme_generate_irq);
-int vme_lm_set(struct device *dev, unsigned long long lm_base, vme_address_t aspace,
- vme_cycle_t cycle)
+/*
+ * Request the location monitor, return resource or NULL
+ */
+struct vme_resource *vme_lm_request(struct device *dev)
{
struct vme_bridge *bridge;
+ struct list_head *lm_pos = NULL;
+ struct vme_lm_resource *allocated_lm = NULL;
+ struct vme_lm_resource *lm = NULL;
+ struct vme_resource *resource = NULL;
bridge = dev_to_bridge(dev);
if (bridge == NULL) {
printk(KERN_ERR "Can't find VME bus\n");
+ goto err_bus;
+ }
+
+ /* Loop through DMA resources */
+ list_for_each(lm_pos, &(bridge->lm_resources)) {
+ lm = list_entry(lm_pos,
+ struct vme_lm_resource, list);
+
+ if (lm == NULL) {
+ printk(KERN_ERR "Registered NULL Location Monitor "
+ "resource\n");
+ continue;
+ }
+
+ /* Find an unlocked controller */
+ mutex_lock(&(lm->mtx));
+ if (lm->locked == 0) {
+ lm->locked = 1;
+ mutex_unlock(&(lm->mtx));
+ allocated_lm = lm;
+ break;
+ }
+ mutex_unlock(&(lm->mtx));
+ }
+
+ /* Check to see if we found a resource */
+ if (allocated_lm == NULL)
+ goto err_lm;
+
+ resource = kmalloc(sizeof(struct vme_resource), GFP_KERNEL);
+ if (resource == NULL) {
+ printk(KERN_ERR "Unable to allocate resource structure\n");
+ goto err_alloc;
+ }
+ resource->type = VME_LM;
+ resource->entry = &(allocated_lm->list);
+
+ return resource;
+
+err_alloc:
+ /* Unlock image */
+ mutex_lock(&(lm->mtx));
+ lm->locked = 0;
+ mutex_unlock(&(lm->mtx));
+err_lm:
+err_bus:
+ return NULL;
+}
+EXPORT_SYMBOL(vme_lm_request);
+
+int vme_lm_count(struct vme_resource *resource)
+{
+ struct vme_lm_resource *lm;
+
+ if (resource->type != VME_LM) {
+ printk(KERN_ERR "Not a Location Monitor resource\n");
+ return -EINVAL;
+ }
+
+ lm = list_entry(resource->entry, struct vme_lm_resource, list);
+
+ return lm->monitors;
+}
+EXPORT_SYMBOL(vme_lm_count);
+
+int vme_lm_set(struct vme_resource *resource, unsigned long long lm_base,
+ vme_address_t aspace, vme_cycle_t cycle)
+{
+ struct vme_bridge *bridge = find_bridge(resource);
+ struct vme_lm_resource *lm;
+
+ if (resource->type != VME_LM) {
+ printk(KERN_ERR "Not a Location Monitor resource\n");
return -EINVAL;
}
+ lm = list_entry(resource->entry, struct vme_lm_resource, list);
+
if (bridge->lm_set == NULL) {
- printk("vme_lm_set not supported\n");
+ printk(KERN_ERR "vme_lm_set not supported\n");
return -EINVAL;
}
- return bridge->lm_set(lm_base, aspace, cycle);
+ /* XXX Check parameters */
+
+ return lm->parent->lm_set(lm, lm_base, aspace, cycle);
}
EXPORT_SYMBOL(vme_lm_set);
-int vme_lm_get(struct device *dev, unsigned long long *lm_base, vme_address_t *aspace,
- vme_cycle_t *cycle)
+int vme_lm_get(struct vme_resource *resource, unsigned long long *lm_base,
+ vme_address_t *aspace, vme_cycle_t *cycle)
{
- struct vme_bridge *bridge;
+ struct vme_bridge *bridge = find_bridge(resource);
+ struct vme_lm_resource *lm;
- bridge = dev_to_bridge(dev);
- if (bridge == NULL) {
- printk(KERN_ERR "Can't find VME bus\n");
+ if (resource->type != VME_LM) {
+ printk(KERN_ERR "Not a Location Monitor resource\n");
return -EINVAL;
}
+ lm = list_entry(resource->entry, struct vme_lm_resource, list);
+
if (bridge->lm_get == NULL) {
- printk("vme_lm_get not supported\n");
+ printk(KERN_ERR "vme_lm_get not supported\n");
return -EINVAL;
}
- return bridge->lm_get(lm_base, aspace, cycle);
+ return bridge->lm_get(lm, lm_base, aspace, cycle);
}
EXPORT_SYMBOL(vme_lm_get);
-int vme_lm_attach(struct device *dev, int monitor, void (*callback)(int))
+int vme_lm_attach(struct vme_resource *resource, int monitor,
+ void (*callback)(int))
{
- struct vme_bridge *bridge;
+ struct vme_bridge *bridge = find_bridge(resource);
+ struct vme_lm_resource *lm;
- bridge = dev_to_bridge(dev);
- if (bridge == NULL) {
- printk(KERN_ERR "Can't find VME bus\n");
+ if (resource->type != VME_LM) {
+ printk(KERN_ERR "Not a Location Monitor resource\n");
return -EINVAL;
}
+ lm = list_entry(resource->entry, struct vme_lm_resource, list);
+
if (bridge->lm_attach == NULL) {
- printk("vme_lm_attach not supported\n");
+ printk(KERN_ERR "vme_lm_attach not supported\n");
return -EINVAL;
}
- return bridge->lm_attach(monitor, callback);
+ return bridge->lm_attach(lm, monitor, callback);
}
EXPORT_SYMBOL(vme_lm_attach);
-int vme_lm_detach(struct device *dev, int monitor)
+int vme_lm_detach(struct vme_resource *resource, int monitor)
{
- struct vme_bridge *bridge;
+ struct vme_bridge *bridge = find_bridge(resource);
+ struct vme_lm_resource *lm;
- bridge = dev_to_bridge(dev);
- if (bridge == NULL) {
- printk(KERN_ERR "Can't find VME bus\n");
+ if (resource->type != VME_LM) {
+ printk(KERN_ERR "Not a Location Monitor resource\n");
return -EINVAL;
}
+ lm = list_entry(resource->entry, struct vme_lm_resource, list);
+
if (bridge->lm_detach == NULL) {
- printk("vme_lm_detach not supported\n");
+ printk(KERN_ERR "vme_lm_detach not supported\n");
return -EINVAL;
}
- return bridge->lm_detach(monitor);
+ return bridge->lm_detach(lm, monitor);
}
EXPORT_SYMBOL(vme_lm_detach);
+void vme_lm_free(struct vme_resource *resource)
+{
+ struct vme_lm_resource *lm;
+
+ if (resource->type != VME_LM) {
+ printk(KERN_ERR "Not a Location Monitor resource\n");
+ return;
+ }
+
+ lm = list_entry(resource->entry, struct vme_lm_resource, list);
+
+ if (mutex_trylock(&(lm->mtx))) {
+ printk(KERN_ERR "Resource busy, can't free\n");
+ return;
+ }
+
+ /* XXX Check to see that there aren't any callbacks still attached */
+
+ lm->locked = 0;
+
+ mutex_unlock(&(lm->mtx));
+}
+EXPORT_SYMBOL(vme_lm_free);
+
int vme_slot_get(struct device *bus)
{
struct vme_bridge *bridge;