Newer
Older
/*
* Char device for device raw access
* Copyright (C) 2005-2007 Kristian Hoegsberg <krh@bitplanet.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <linux/compat.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/firewire-cdev.h>
#include <linux/idr.h>
Jay Fenlason, Stefan Richter
committed
#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/kref.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/poll.h>
#include <linux/preempt.h>
#include <linux/uaccess.h>
#include <linux/vmalloc.h>
#include <linux/wait.h>
Jay Fenlason, Stefan Richter
committed
#include <linux/workqueue.h>
#include <asm/system.h>
struct client {
struct fw_device *device;
bool in_shutdown;
struct idr resource_idr;
struct list_head event_list;
wait_queue_head_t wait;
u64 bus_reset_closure;
Kristian Høgsberg
committed
struct fw_iso_context *iso_context;
Kristian Høgsberg
committed
u64 iso_closure;
Kristian Høgsberg
committed
struct fw_iso_buffer buffer;
unsigned long vm_start;
struct list_head link;
static inline void client_get(struct client *client)
{
kref_get(&client->kref);
}
static void client_release(struct kref *kref)
{
struct client *client = container_of(kref, struct client, kref);
fw_device_put(client->device);
kfree(client);
}
static void client_put(struct client *client)
{
kref_put(&client->kref, client_release);
}
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
struct client_resource;
typedef void (*client_resource_release_fn_t)(struct client *,
struct client_resource *);
struct client_resource {
client_resource_release_fn_t release;
int handle;
};
struct address_handler_resource {
struct client_resource resource;
struct fw_address_handler handler;
__u64 closure;
struct client *client;
};
struct outbound_transaction_resource {
struct client_resource resource;
struct fw_transaction transaction;
};
struct inbound_transaction_resource {
struct client_resource resource;
struct fw_request *request;
void *data;
size_t length;
};
struct descriptor_resource {
struct client_resource resource;
struct fw_descriptor descriptor;
u32 data[0];
};
Jay Fenlason, Stefan Richter
committed
struct iso_resource {
struct client_resource resource;
struct client *client;
/* Schedule work and access todo only with client->lock held. */
struct delayed_work work;
enum {ISO_RES_ALLOC, ISO_RES_REALLOC, ISO_RES_DEALLOC,
ISO_RES_ALLOC_ONCE, ISO_RES_DEALLOC_ONCE,} todo;
Jay Fenlason, Stefan Richter
committed
int generation;
u64 channels;
s32 bandwidth;
__be32 transaction_data[2];
Jay Fenlason, Stefan Richter
committed
struct iso_resource_event *e_alloc, *e_dealloc;
};
static void release_iso_resource(struct client *, struct client_resource *);
static void schedule_iso_resource(struct iso_resource *r, unsigned long delay)
{
client_get(r->client);
if (!schedule_delayed_work(&r->work, delay))
client_put(r->client);
}
static void schedule_if_iso_resource(struct client_resource *resource)
{
if (resource->release == release_iso_resource)
schedule_iso_resource(container_of(resource,
struct iso_resource, resource), 0);
}
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
/*
* dequeue_event() just kfree()'s the event, so the event has to be
* the first field in a struct XYZ_event.
*/
struct event {
struct { void *data; size_t size; } v[2];
struct list_head link;
};
struct bus_reset_event {
struct event event;
struct fw_cdev_event_bus_reset reset;
};
struct outbound_transaction_event {
struct event event;
struct client *client;
struct outbound_transaction_resource r;
struct fw_cdev_event_response response;
};
struct inbound_transaction_event {
struct event event;
struct fw_cdev_event_request request;
};
struct iso_interrupt_event {
struct event event;
struct fw_cdev_event_iso_interrupt interrupt;
};
Jay Fenlason, Stefan Richter
committed
struct iso_resource_event {
struct event event;
struct fw_cdev_event_iso_resource resource;
};
static inline void __user *u64_to_uptr(__u64 value)
{
return (void __user *)(unsigned long)value;
}
static inline __u64 uptr_to_u64(void __user *ptr)
{
return (__u64)(unsigned long)ptr;
}
static int fw_device_op_open(struct inode *inode, struct file *file)
{
struct fw_device *device;
struct client *client;
device = fw_device_get_by_devt(inode->i_rdev);
Kristian Høgsberg
committed
if (device == NULL)
Loading
Loading full blame...