Blame view
drivers/firewire/nosy.c
17.5 KB
b5e477290 firewire: nosy: m... |
1 2 3 |
/* * nosy - Snoop mode driver for TI PCILynx 1394 controllers * Copyright (C) 2002-2007 Kristian Høgsberg |
286468210 firewire: new dri... |
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
* * 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. */ |
7429b17d3 firewire: nosy: u... |
19 |
#include <linux/device.h> |
286468210 firewire: new dri... |
20 |
#include <linux/errno.h> |
b5e477290 firewire: nosy: m... |
21 |
#include <linux/fs.h> |
286468210 firewire: new dri... |
22 |
#include <linux/init.h> |
b5e477290 firewire: nosy: m... |
23 24 25 |
#include <linux/interrupt.h> #include <linux/io.h> #include <linux/kernel.h> |
424d66ced firewire: nosy: f... |
26 |
#include <linux/kref.h> |
b5e477290 firewire: nosy: m... |
27 28 |
#include <linux/miscdevice.h> #include <linux/module.h> |
424d66ced firewire: nosy: f... |
29 |
#include <linux/mutex.h> |
286468210 firewire: new dri... |
30 |
#include <linux/pci.h> |
286468210 firewire: new dri... |
31 |
#include <linux/poll.h> |
b5e477290 firewire: nosy: m... |
32 33 34 35 36 37 |
#include <linux/sched.h> /* required for linux/wait.h */ #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/timex.h> #include <linux/uaccess.h> #include <linux/wait.h> |
60063497a atomic: use <linu... |
38 |
#include <linux/atomic.h> |
b5e477290 firewire: nosy: m... |
39 |
#include <asm/byteorder.h> |
286468210 firewire: new dri... |
40 41 42 43 44 45 |
#include "nosy.h" #include "nosy-user.h" #define TCODE_PHY_PACKET 0x10 #define PCI_DEVICE_ID_TI_PCILYNX 0x8000 |
b5e477290 firewire: nosy: m... |
46 |
static char driver_name[] = KBUILD_MODNAME; |
286468210 firewire: new dri... |
47 |
|
286468210 firewire: new dri... |
48 49 |
/* this is the physical layout of a PCL, its size is 128 bytes */ struct pcl { |
fd8c8d46c firewire: nosy: e... |
50 51 52 53 54 55 56 57 58 59 60 |
__le32 next; __le32 async_error_next; u32 user_data; __le32 pcl_status; __le32 remaining_transfer_count; __le32 next_data_buffer; struct { __le32 control; __le32 pointer; } buffer[13]; }; |
286468210 firewire: new dri... |
61 62 |
struct packet { |
b5e477290 firewire: nosy: m... |
63 |
unsigned int length; |
286468210 firewire: new dri... |
64 65 66 67 68 69 70 71 |
char data[0]; }; struct packet_buffer { char *data; size_t capacity; long total_packet_count, lost_packet_count; atomic_t size; |
b5e477290 firewire: nosy: m... |
72 73 |
struct packet *head, *tail; wait_queue_head_t wait; |
286468210 firewire: new dri... |
74 75 76 77 |
}; struct pcilynx { struct pci_dev *pci_device; |
c89db7b8b firewire: nosy: a... |
78 |
__iomem char *registers; |
286468210 firewire: new dri... |
79 80 |
struct pcl *rcv_start_pcl, *rcv_pcl; |
fd8c8d46c firewire: nosy: e... |
81 |
__le32 *rcv_buffer; |
286468210 firewire: new dri... |
82 83 84 85 86 87 88 |
dma_addr_t rcv_start_pcl_bus, rcv_pcl_bus, rcv_buffer_bus; spinlock_t client_list_lock; struct list_head client_list; struct miscdevice misc; |
424d66ced firewire: nosy: f... |
89 90 |
struct list_head link; struct kref kref; |
286468210 firewire: new dri... |
91 |
}; |
424d66ced firewire: nosy: f... |
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
static inline struct pcilynx * lynx_get(struct pcilynx *lynx) { kref_get(&lynx->kref); return lynx; } static void lynx_release(struct kref *kref) { kfree(container_of(kref, struct pcilynx, kref)); } static inline void lynx_put(struct pcilynx *lynx) { kref_put(&lynx->kref, lynx_release); } |
286468210 firewire: new dri... |
111 112 |
struct client { struct pcilynx *lynx; |
c7b2a99c6 firewire: nosy: c... |
113 |
u32 tcode_mask; |
286468210 firewire: new dri... |
114 115 116 |
struct packet_buffer buffer; struct list_head link; }; |
424d66ced firewire: nosy: f... |
117 118 |
static DEFINE_MUTEX(card_mutex); static LIST_HEAD(card_list); |
286468210 firewire: new dri... |
119 120 121 122 123 124 125 126 127 128 129 130 |
static int packet_buffer_init(struct packet_buffer *buffer, size_t capacity) { buffer->data = kmalloc(capacity, GFP_KERNEL); if (buffer->data == NULL) return -ENOMEM; buffer->head = (struct packet *) buffer->data; buffer->tail = (struct packet *) buffer->data; buffer->capacity = capacity; buffer->lost_packet_count = 0; atomic_set(&buffer->size, 0); |
b5e477290 firewire: nosy: m... |
131 |
init_waitqueue_head(&buffer->wait); |
286468210 firewire: new dri... |
132 133 134 135 136 137 138 139 140 141 142 |
return 0; } static void packet_buffer_destroy(struct packet_buffer *buffer) { kfree(buffer->data); } static int |
c89db7b8b firewire: nosy: a... |
143 |
packet_buffer_get(struct client *client, char __user *data, size_t user_length) |
286468210 firewire: new dri... |
144 |
{ |
424d66ced firewire: nosy: f... |
145 |
struct packet_buffer *buffer = &client->buffer; |
286468210 firewire: new dri... |
146 147 148 149 |
size_t length; char *end; if (wait_event_interruptible(buffer->wait, |
424d66ced firewire: nosy: f... |
150 151 |
atomic_read(&buffer->size) > 0) || list_empty(&client->lynx->link)) |
286468210 firewire: new dri... |
152 |
return -ERESTARTSYS; |
424d66ced firewire: nosy: f... |
153 154 |
if (atomic_read(&buffer->size) == 0) return -ENODEV; |
286468210 firewire: new dri... |
155 156 157 158 159 160 161 162 163 |
/* FIXME: Check length <= user_length. */ end = buffer->data + buffer->capacity; length = buffer->head->length; if (&buffer->head->data[length] < end) { if (copy_to_user(data, buffer->head->data, length)) return -EFAULT; buffer->head = (struct packet *) &buffer->head->data[length]; |
b5e477290 firewire: nosy: m... |
164 |
} else { |
286468210 firewire: new dri... |
165 166 167 168 169 170 171 172 |
size_t split = end - buffer->head->data; if (copy_to_user(data, buffer->head->data, split)) return -EFAULT; if (copy_to_user(data + split, buffer->data, length - split)) return -EFAULT; buffer->head = (struct packet *) &buffer->data[length - split]; } |
b5e477290 firewire: nosy: m... |
173 174 |
/* * Decrease buffer->size as the last thing, since this is what |
286468210 firewire: new dri... |
175 |
* keeps the interrupt from overwriting the packet we are |
b5e477290 firewire: nosy: m... |
176 177 178 |
* retrieving from the buffer. */ atomic_sub(sizeof(struct packet) + length, &buffer->size); |
286468210 firewire: new dri... |
179 180 181 182 183 184 185 186 187 188 |
return length; } static void packet_buffer_put(struct packet_buffer *buffer, void *data, size_t length) { char *end; buffer->total_packet_count++; |
b5e477290 firewire: nosy: m... |
189 190 |
if (buffer->capacity < atomic_read(&buffer->size) + sizeof(struct packet) + length) { |
286468210 firewire: new dri... |
191 192 193 194 195 196 197 198 199 200 |
buffer->lost_packet_count++; return; } end = buffer->data + buffer->capacity; buffer->tail->length = length; if (&buffer->tail->data[length] < end) { memcpy(buffer->tail->data, data, length); buffer->tail = (struct packet *) &buffer->tail->data[length]; |
b5e477290 firewire: nosy: m... |
201 |
} else { |
286468210 firewire: new dri... |
202 203 204 205 206 207 |
size_t split = end - buffer->tail->data; memcpy(buffer->tail->data, data, split); memcpy(buffer->data, data + split, length - split); buffer->tail = (struct packet *) &buffer->data[length - split]; } |
b5e477290 firewire: nosy: m... |
208 |
|
286468210 firewire: new dri... |
209 |
/* Finally, adjust buffer size and wake up userspace reader. */ |
b5e477290 firewire: nosy: m... |
210 |
atomic_add(sizeof(struct packet) + length, &buffer->size); |
286468210 firewire: new dri... |
211 212 213 214 215 216 |
wake_up_interruptible(&buffer->wait); } static inline void reg_write(struct pcilynx *lynx, int offset, u32 data) { |
b5e477290 firewire: nosy: m... |
217 |
writel(data, lynx->registers + offset); |
286468210 firewire: new dri... |
218 219 220 221 222 |
} static inline u32 reg_read(struct pcilynx *lynx, int offset) { |
b5e477290 firewire: nosy: m... |
223 |
return readl(lynx->registers + offset); |
286468210 firewire: new dri... |
224 225 226 227 228 |
} static inline void reg_set_bits(struct pcilynx *lynx, int offset, u32 mask) { |
b5e477290 firewire: nosy: m... |
229 |
reg_write(lynx, offset, (reg_read(lynx, offset) | mask)); |
286468210 firewire: new dri... |
230 |
} |
b5e477290 firewire: nosy: m... |
231 232 233 234 235 236 237 |
/* * Maybe the pcl programs could be set up to just append data instead * of using a whole packet. */ static inline void run_pcl(struct pcilynx *lynx, dma_addr_t pcl_bus, int dmachan) |
286468210 firewire: new dri... |
238 |
{ |
b5e477290 firewire: nosy: m... |
239 240 241 |
reg_write(lynx, DMA0_CURRENT_PCL + dmachan * 0x20, pcl_bus); reg_write(lynx, DMA0_CHAN_CTRL + dmachan * 0x20, DMA_CHAN_CTRL_ENABLE | DMA_CHAN_CTRL_LINK); |
286468210 firewire: new dri... |
242 243 244 245 246 |
} static int set_phy_reg(struct pcilynx *lynx, int addr, int val) { |
b5e477290 firewire: nosy: m... |
247 |
if (addr > 15) { |
7429b17d3 firewire: nosy: u... |
248 249 250 |
dev_err(&lynx->pci_device->dev, "PHY register address %d out of range ", addr); |
b5e477290 firewire: nosy: m... |
251 252 |
return -1; } |
b5e477290 firewire: nosy: m... |
253 |
if (val > 0xff) { |
7429b17d3 firewire: nosy: u... |
254 255 256 |
dev_err(&lynx->pci_device->dev, "PHY register value %d out of range ", val); |
b5e477290 firewire: nosy: m... |
257 258 |
return -1; } |
b5e477290 firewire: nosy: m... |
259 |
reg_write(lynx, LINK_PHY, LINK_PHY_WRITE | |
286468210 firewire: new dri... |
260 |
LINK_PHY_ADDR(addr) | LINK_PHY_WDATA(val)); |
b5e477290 firewire: nosy: m... |
261 |
return 0; |
286468210 firewire: new dri... |
262 |
} |
55e77c06c firewire: nosy: u... |
263 264 |
static int nosy_open(struct inode *inode, struct file *file) |
286468210 firewire: new dri... |
265 |
{ |
55e77c06c firewire: nosy: u... |
266 |
int minor = iminor(inode); |
286468210 firewire: new dri... |
267 |
struct client *client; |
424d66ced firewire: nosy: f... |
268 269 270 271 272 273 274 275 276 277 |
struct pcilynx *tmp, *lynx = NULL; mutex_lock(&card_mutex); list_for_each_entry(tmp, &card_list, link) if (tmp->misc.minor == minor) { lynx = lynx_get(tmp); break; } mutex_unlock(&card_mutex); if (lynx == NULL) |
55e77c06c firewire: nosy: u... |
278 |
return -ENODEV; |
286468210 firewire: new dri... |
279 |
client = kmalloc(sizeof *client, GFP_KERNEL); |
55e77c06c firewire: nosy: u... |
280 |
if (client == NULL) |
424d66ced firewire: nosy: f... |
281 |
goto fail; |
55e77c06c firewire: nosy: u... |
282 |
|
286468210 firewire: new dri... |
283 |
client->tcode_mask = ~0; |
424d66ced firewire: nosy: f... |
284 |
client->lynx = lynx; |
286468210 firewire: new dri... |
285 |
INIT_LIST_HEAD(&client->link); |
424d66ced firewire: nosy: f... |
286 287 |
if (packet_buffer_init(&client->buffer, 128 * 1024) < 0) goto fail; |
286468210 firewire: new dri... |
288 |
|
55e77c06c firewire: nosy: u... |
289 |
file->private_data = client; |
286468210 firewire: new dri... |
290 |
|
60a74a6ff firewire: nosy: c... |
291 |
return nonseekable_open(inode, file); |
424d66ced firewire: nosy: f... |
292 293 294 295 296 |
fail: kfree(client); lynx_put(lynx); return -ENOMEM; |
286468210 firewire: new dri... |
297 298 299 |
} static int |
55e77c06c firewire: nosy: u... |
300 |
nosy_release(struct inode *inode, struct file *file) |
286468210 firewire: new dri... |
301 |
{ |
55e77c06c firewire: nosy: u... |
302 |
struct client *client = file->private_data; |
424d66ced firewire: nosy: f... |
303 |
struct pcilynx *lynx = client->lynx; |
286468210 firewire: new dri... |
304 |
|
424d66ced firewire: nosy: f... |
305 |
spin_lock_irq(&lynx->client_list_lock); |
55e77c06c firewire: nosy: u... |
306 |
list_del_init(&client->link); |
424d66ced firewire: nosy: f... |
307 |
spin_unlock_irq(&lynx->client_list_lock); |
286468210 firewire: new dri... |
308 |
|
55e77c06c firewire: nosy: u... |
309 310 |
packet_buffer_destroy(&client->buffer); kfree(client); |
424d66ced firewire: nosy: f... |
311 |
lynx_put(lynx); |
286468210 firewire: new dri... |
312 |
|
b5e477290 firewire: nosy: m... |
313 |
return 0; |
286468210 firewire: new dri... |
314 315 316 317 318 319 |
} static unsigned int nosy_poll(struct file *file, poll_table *pt) { struct client *client = file->private_data; |
424d66ced firewire: nosy: f... |
320 |
unsigned int ret = 0; |
286468210 firewire: new dri... |
321 322 323 324 |
poll_wait(file, &client->buffer.wait, pt); if (atomic_read(&client->buffer.size) > 0) |
424d66ced firewire: nosy: f... |
325 326 327 328 329 330 |
ret = POLLIN | POLLRDNORM; if (list_empty(&client->lynx->link)) ret |= POLLHUP; return ret; |
286468210 firewire: new dri... |
331 332 333 |
} static ssize_t |
c89db7b8b firewire: nosy: a... |
334 |
nosy_read(struct file *file, char __user *buffer, size_t count, loff_t *offset) |
286468210 firewire: new dri... |
335 336 |
{ struct client *client = file->private_data; |
424d66ced firewire: nosy: f... |
337 |
return packet_buffer_get(client, buffer, count); |
286468210 firewire: new dri... |
338 |
} |
c7b2a99c6 firewire: nosy: c... |
339 340 |
static long nosy_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
286468210 firewire: new dri... |
341 342 |
{ struct client *client = file->private_data; |
c7b2a99c6 firewire: nosy: c... |
343 |
spinlock_t *client_list_lock = &client->lynx->client_list_lock; |
b5e477290 firewire: nosy: m... |
344 |
struct nosy_stats stats; |
286468210 firewire: new dri... |
345 346 |
switch (cmd) { |
b5e477290 firewire: nosy: m... |
347 |
case NOSY_IOC_GET_STATS: |
c7b2a99c6 firewire: nosy: c... |
348 |
spin_lock_irq(client_list_lock); |
286468210 firewire: new dri... |
349 |
stats.total_packet_count = client->buffer.total_packet_count; |
c7b2a99c6 firewire: nosy: c... |
350 351 |
stats.lost_packet_count = client->buffer.lost_packet_count; spin_unlock_irq(client_list_lock); |
c89db7b8b firewire: nosy: a... |
352 |
if (copy_to_user((void __user *) arg, &stats, sizeof stats)) |
286468210 firewire: new dri... |
353 354 355 |
return -EFAULT; else return 0; |
b5e477290 firewire: nosy: m... |
356 |
|
286468210 firewire: new dri... |
357 |
case NOSY_IOC_START: |
55e77c06c firewire: nosy: u... |
358 359 360 |
spin_lock_irq(client_list_lock); list_add_tail(&client->link, &client->lynx->client_list); spin_unlock_irq(client_list_lock); |
286468210 firewire: new dri... |
361 362 363 |
return 0; case NOSY_IOC_STOP: |
55e77c06c firewire: nosy: u... |
364 365 366 |
spin_lock_irq(client_list_lock); list_del_init(&client->link); spin_unlock_irq(client_list_lock); |
286468210 firewire: new dri... |
367 368 369 |
return 0; case NOSY_IOC_FILTER: |
c7b2a99c6 firewire: nosy: c... |
370 |
spin_lock_irq(client_list_lock); |
286468210 firewire: new dri... |
371 |
client->tcode_mask = arg; |
c7b2a99c6 firewire: nosy: c... |
372 |
spin_unlock_irq(client_list_lock); |
55e77c06c firewire: nosy: u... |
373 |
|
286468210 firewire: new dri... |
374 375 376 377 378 379 380 |
return 0; default: return -EINVAL; /* Flush buffer, configure filter. */ } } |
b5e477290 firewire: nosy: m... |
381 |
static const struct file_operations nosy_ops = { |
c7b2a99c6 firewire: nosy: c... |
382 383 384 385 386 387 |
.owner = THIS_MODULE, .read = nosy_read, .unlocked_ioctl = nosy_ioctl, .poll = nosy_poll, .open = nosy_open, .release = nosy_release, |
286468210 firewire: new dri... |
388 389 390 |
}; #define PHY_PACKET_SIZE 12 /* 1 payload, 1 inverse, 1 ack = 3 quadlets */ |
286468210 firewire: new dri... |
391 |
static void |
685c3f80b firewire: nosy: u... |
392 |
packet_irq_handler(struct pcilynx *lynx) |
286468210 firewire: new dri... |
393 |
{ |
286468210 firewire: new dri... |
394 |
struct client *client; |
fd8c8d46c firewire: nosy: e... |
395 |
u32 tcode_mask, tcode; |
286468210 firewire: new dri... |
396 |
size_t length; |
286468210 firewire: new dri... |
397 398 399 |
struct timeval tv; /* FIXME: Also report rcv_speed. */ |
fd8c8d46c firewire: nosy: e... |
400 401 |
length = __le32_to_cpu(lynx->rcv_pcl->pcl_status) & 0x00001fff; tcode = __le32_to_cpu(lynx->rcv_buffer[1]) >> 4 & 0xf; |
286468210 firewire: new dri... |
402 403 |
do_gettimeofday(&tv); |
fd8c8d46c firewire: nosy: e... |
404 |
lynx->rcv_buffer[0] = (__force __le32)tv.tv_usec; |
286468210 firewire: new dri... |
405 406 407 408 |
if (length == PHY_PACKET_SIZE) tcode_mask = 1 << TCODE_PHY_PACKET; else |
fd8c8d46c firewire: nosy: e... |
409 |
tcode_mask = 1 << tcode; |
286468210 firewire: new dri... |
410 |
|
685c3f80b firewire: nosy: u... |
411 |
spin_lock(&lynx->client_list_lock); |
286468210 firewire: new dri... |
412 |
|
b5e477290 firewire: nosy: m... |
413 |
list_for_each_entry(client, &lynx->client_list, link) |
286468210 firewire: new dri... |
414 |
if (client->tcode_mask & tcode_mask) |
b5e477290 firewire: nosy: m... |
415 |
packet_buffer_put(&client->buffer, |
286468210 firewire: new dri... |
416 |
lynx->rcv_buffer, length + 4); |
286468210 firewire: new dri... |
417 |
|
685c3f80b firewire: nosy: u... |
418 |
spin_unlock(&lynx->client_list_lock); |
286468210 firewire: new dri... |
419 420 421 |
} static void |
685c3f80b firewire: nosy: u... |
422 |
bus_reset_irq_handler(struct pcilynx *lynx) |
286468210 firewire: new dri... |
423 |
{ |
286468210 firewire: new dri... |
424 425 426 427 |
struct client *client; struct timeval tv; do_gettimeofday(&tv); |
685c3f80b firewire: nosy: u... |
428 |
spin_lock(&lynx->client_list_lock); |
286468210 firewire: new dri... |
429 |
|
b5e477290 firewire: nosy: m... |
430 |
list_for_each_entry(client, &lynx->client_list, link) |
286468210 firewire: new dri... |
431 |
packet_buffer_put(&client->buffer, &tv.tv_usec, 4); |
286468210 firewire: new dri... |
432 |
|
685c3f80b firewire: nosy: u... |
433 |
spin_unlock(&lynx->client_list_lock); |
286468210 firewire: new dri... |
434 |
} |
286468210 firewire: new dri... |
435 436 437 |
static irqreturn_t irq_handler(int irq, void *device) { |
b5e477290 firewire: nosy: m... |
438 |
struct pcilynx *lynx = device; |
286468210 firewire: new dri... |
439 |
u32 pci_int_status; |
b5e477290 firewire: nosy: m... |
440 441 |
pci_int_status = reg_read(lynx, PCI_INT_STATUS); |
286468210 firewire: new dri... |
442 |
|
165476671 firewire: nosy: f... |
443 444 445 |
if (pci_int_status == ~0) /* Card was ejected. */ return IRQ_NONE; |
286468210 firewire: new dri... |
446 447 448 449 450 451 452 453 454 455 456 |
if ((pci_int_status & PCI_INT_INT_PEND) == 0) /* Not our interrupt, bail out quickly. */ return IRQ_NONE; if ((pci_int_status & PCI_INT_P1394_INT) != 0) { u32 link_int_status; link_int_status = reg_read(lynx, LINK_INT_STATUS); reg_write(lynx, LINK_INT_STATUS, link_int_status); if ((link_int_status & LINK_INT_PHY_BUSRESET) > 0) |
685c3f80b firewire: nosy: u... |
457 |
bus_reset_irq_handler(lynx); |
286468210 firewire: new dri... |
458 459 460 461 462 463 464 465 466 |
} /* Clear the PCI_INT_STATUS register only after clearing the * LINK_INT_STATUS register; otherwise the PCI_INT_P1394 will * be set again immediately. */ reg_write(lynx, PCI_INT_STATUS, pci_int_status); if ((pci_int_status & PCI_INT_DMA0_HLT) > 0) { |
685c3f80b firewire: nosy: u... |
467 |
packet_irq_handler(lynx); |
286468210 firewire: new dri... |
468 469 470 471 472 473 474 475 476 |
run_pcl(lynx, lynx->rcv_start_pcl_bus, 0); } return IRQ_HANDLED; } static void remove_card(struct pci_dev *dev) { |
424d66ced firewire: nosy: f... |
477 478 |
struct pcilynx *lynx = pci_get_drvdata(dev); struct client *client; |
286468210 firewire: new dri... |
479 |
|
424d66ced firewire: nosy: f... |
480 481 482 483 |
mutex_lock(&card_mutex); list_del_init(&lynx->link); misc_deregister(&lynx->misc); mutex_unlock(&card_mutex); |
286468210 firewire: new dri... |
484 485 486 |
reg_write(lynx, PCI_INT_ENABLE, 0); free_irq(lynx->pci_device->irq, lynx); |
424d66ced firewire: nosy: f... |
487 488 489 490 |
spin_lock_irq(&lynx->client_list_lock); list_for_each_entry(client, &lynx->client_list, link) wake_up_interruptible(&client->buffer.wait); spin_unlock_irq(&lynx->client_list_lock); |
b5e477290 firewire: nosy: m... |
491 |
pci_free_consistent(lynx->pci_device, sizeof(struct pcl), |
286468210 firewire: new dri... |
492 |
lynx->rcv_start_pcl, lynx->rcv_start_pcl_bus); |
b5e477290 firewire: nosy: m... |
493 |
pci_free_consistent(lynx->pci_device, sizeof(struct pcl), |
286468210 firewire: new dri... |
494 495 496 497 498 |
lynx->rcv_pcl, lynx->rcv_pcl_bus); pci_free_consistent(lynx->pci_device, PAGE_SIZE, lynx->rcv_buffer, lynx->rcv_buffer_bus); iounmap(lynx->registers); |
b6d9c125e firewire: nosy: h... |
499 |
pci_disable_device(dev); |
424d66ced firewire: nosy: f... |
500 |
lynx_put(lynx); |
286468210 firewire: new dri... |
501 502 503 |
} #define RCV_BUFFER_SIZE (16 * 1024) |
286468210 firewire: new dri... |
504 505 506 |
static int __devinit add_card(struct pci_dev *dev, const struct pci_device_id *unused) { |
b5e477290 firewire: nosy: m... |
507 |
struct pcilynx *lynx; |
286468210 firewire: new dri... |
508 |
u32 p, end; |
b6d9c125e firewire: nosy: h... |
509 |
int ret, i; |
286468210 firewire: new dri... |
510 |
|
b5e477290 firewire: nosy: m... |
511 |
if (pci_set_dma_mask(dev, 0xffffffff)) { |
7429b17d3 firewire: nosy: u... |
512 513 514 |
dev_err(&dev->dev, "DMA address limits not supported for PCILynx hardware "); |
b5e477290 firewire: nosy: m... |
515 516 517 |
return -ENXIO; } if (pci_enable_device(dev)) { |
7429b17d3 firewire: nosy: u... |
518 519 |
dev_err(&dev->dev, "Failed to enable PCILynx hardware "); |
b5e477290 firewire: nosy: m... |
520 521 522 |
return -ENXIO; } pci_set_master(dev); |
286468210 firewire: new dri... |
523 524 |
lynx = kzalloc(sizeof *lynx, GFP_KERNEL); |
b5e477290 firewire: nosy: m... |
525 |
if (lynx == NULL) { |
7429b17d3 firewire: nosy: u... |
526 527 |
dev_err(&dev->dev, "Failed to allocate control structure "); |
b6d9c125e firewire: nosy: h... |
528 529 |
ret = -ENOMEM; goto fail_disable; |
b5e477290 firewire: nosy: m... |
530 531 532 |
} lynx->pci_device = dev; pci_set_drvdata(dev, lynx); |
286468210 firewire: new dri... |
533 534 535 |
spin_lock_init(&lynx->client_list_lock); INIT_LIST_HEAD(&lynx->client_list); |
424d66ced firewire: nosy: f... |
536 |
kref_init(&lynx->kref); |
286468210 firewire: new dri... |
537 |
|
b5e477290 firewire: nosy: m... |
538 539 540 541 542 543 544 545 546 547 |
lynx->registers = ioremap_nocache(pci_resource_start(dev, 0), PCILYNX_MAX_REGISTER); lynx->rcv_start_pcl = pci_alloc_consistent(lynx->pci_device, sizeof(struct pcl), &lynx->rcv_start_pcl_bus); lynx->rcv_pcl = pci_alloc_consistent(lynx->pci_device, sizeof(struct pcl), &lynx->rcv_pcl_bus); lynx->rcv_buffer = pci_alloc_consistent(lynx->pci_device, RCV_BUFFER_SIZE, &lynx->rcv_buffer_bus); if (lynx->rcv_start_pcl == NULL || |
286468210 firewire: new dri... |
548 |
lynx->rcv_pcl == NULL || |
b5e477290 firewire: nosy: m... |
549 |
lynx->rcv_buffer == NULL) { |
7429b17d3 firewire: nosy: u... |
550 551 |
dev_err(&dev->dev, "Failed to allocate receive buffer "); |
b6d9c125e firewire: nosy: h... |
552 553 |
ret = -ENOMEM; goto fail_deallocate; |
b5e477290 firewire: nosy: m... |
554 |
} |
fd8c8d46c firewire: nosy: e... |
555 556 557 |
lynx->rcv_start_pcl->next = cpu_to_le32(lynx->rcv_pcl_bus); lynx->rcv_pcl->next = cpu_to_le32(PCL_NEXT_INVALID); lynx->rcv_pcl->async_error_next = cpu_to_le32(PCL_NEXT_INVALID); |
286468210 firewire: new dri... |
558 |
|
b5e477290 firewire: nosy: m... |
559 |
lynx->rcv_pcl->buffer[0].control = |
fd8c8d46c firewire: nosy: e... |
560 561 562 |
cpu_to_le32(PCL_CMD_RCV | PCL_BIGENDIAN | 2044); lynx->rcv_pcl->buffer[0].pointer = cpu_to_le32(lynx->rcv_buffer_bus + 4); |
286468210 firewire: new dri... |
563 564 565 566 |
p = lynx->rcv_buffer_bus + 2048; end = lynx->rcv_buffer_bus + RCV_BUFFER_SIZE; for (i = 1; p < end; i++, p += 2048) { lynx->rcv_pcl->buffer[i].control = |
fd8c8d46c firewire: nosy: e... |
567 568 |
cpu_to_le32(PCL_CMD_RCV | PCL_BIGENDIAN | 2048); lynx->rcv_pcl->buffer[i].pointer = cpu_to_le32(p); |
286468210 firewire: new dri... |
569 |
} |
fd8c8d46c firewire: nosy: e... |
570 |
lynx->rcv_pcl->buffer[i - 1].control |= cpu_to_le32(PCL_LAST_BUFF); |
286468210 firewire: new dri... |
571 |
|
b5e477290 firewire: nosy: m... |
572 573 574 575 |
reg_set_bits(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET); /* Fix buggy cards with autoboot pin not tied low: */ reg_write(lynx, DMA0_CHAN_CTRL, 0); reg_write(lynx, DMA_GLOBAL_REGISTER, 0x00 << 24); |
286468210 firewire: new dri... |
576 577 |
#if 0 |
b5e477290 firewire: nosy: m... |
578 579 580 581 582 583 584 585 586 587 588 |
/* now, looking for PHY register set */ if ((get_phy_reg(lynx, 2) & 0xe0) == 0xe0) { lynx->phyic.reg_1394a = 1; PRINT(KERN_INFO, lynx->id, "found 1394a conform PHY (using extended register set)"); lynx->phyic.vendor = get_phy_vendorid(lynx); lynx->phyic.product = get_phy_productid(lynx); } else { lynx->phyic.reg_1394a = 0; PRINT(KERN_INFO, lynx->id, "found old 1394 PHY"); } |
286468210 firewire: new dri... |
589 590 591 592 |
#endif /* Setup the general receive FIFO max size. */ reg_write(lynx, FIFO_SIZES, 255); |
b5e477290 firewire: nosy: m... |
593 |
reg_set_bits(lynx, PCI_INT_ENABLE, PCI_INT_DMA_ALL); |
286468210 firewire: new dri... |
594 |
|
b5e477290 firewire: nosy: m... |
595 |
reg_write(lynx, LINK_INT_ENABLE, |
286468210 firewire: new dri... |
596 597 598 599 600 601 602 603 604 605 606 607 608 |
LINK_INT_PHY_TIME_OUT | LINK_INT_PHY_REG_RCVD | LINK_INT_PHY_BUSRESET | LINK_INT_IT_STUCK | LINK_INT_AT_STUCK | LINK_INT_SNTRJ | LINK_INT_TC_ERR | LINK_INT_GRF_OVER_FLOW | LINK_INT_ITF_UNDER_FLOW | LINK_INT_ATF_UNDER_FLOW); /* Disable the L flag in self ID packets. */ set_phy_reg(lynx, 4, 0); /* Put this baby into snoop mode */ reg_set_bits(lynx, LINK_CONTROL, LINK_CONTROL_SNOOP_ENABLE); run_pcl(lynx, lynx->rcv_start_pcl_bus, 0); |
b5e477290 firewire: nosy: m... |
609 610 |
if (request_irq(dev->irq, irq_handler, IRQF_SHARED, driver_name, lynx)) { |
7429b17d3 firewire: nosy: u... |
611 612 613 |
dev_err(&dev->dev, "Failed to allocate shared interrupt %d ", dev->irq); |
b6d9c125e firewire: nosy: h... |
614 615 |
ret = -EIO; goto fail_deallocate; |
b5e477290 firewire: nosy: m... |
616 |
} |
286468210 firewire: new dri... |
617 618 619 620 621 |
lynx->misc.parent = &dev->dev; lynx->misc.minor = MISC_DYNAMIC_MINOR; lynx->misc.name = "nosy"; lynx->misc.fops = &nosy_ops; |
424d66ced firewire: nosy: f... |
622 623 |
mutex_lock(&card_mutex); |
b6d9c125e firewire: nosy: h... |
624 625 |
ret = misc_register(&lynx->misc); if (ret) { |
7429b17d3 firewire: nosy: u... |
626 627 |
dev_err(&dev->dev, "Failed to register misc char device "); |
424d66ced firewire: nosy: f... |
628 |
mutex_unlock(&card_mutex); |
b6d9c125e firewire: nosy: h... |
629 |
goto fail_free_irq; |
b5e477290 firewire: nosy: m... |
630 |
} |
424d66ced firewire: nosy: f... |
631 632 |
list_add_tail(&lynx->link, &card_list); mutex_unlock(&card_mutex); |
286468210 firewire: new dri... |
633 |
|
7429b17d3 firewire: nosy: u... |
634 635 636 |
dev_info(&dev->dev, "Initialized PCILynx IEEE1394 card, irq=%d ", dev->irq); |
286468210 firewire: new dri... |
637 |
|
b5e477290 firewire: nosy: m... |
638 |
return 0; |
b6d9c125e firewire: nosy: h... |
639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 |
fail_free_irq: reg_write(lynx, PCI_INT_ENABLE, 0); free_irq(lynx->pci_device->irq, lynx); fail_deallocate: if (lynx->rcv_start_pcl) pci_free_consistent(lynx->pci_device, sizeof(struct pcl), lynx->rcv_start_pcl, lynx->rcv_start_pcl_bus); if (lynx->rcv_pcl) pci_free_consistent(lynx->pci_device, sizeof(struct pcl), lynx->rcv_pcl, lynx->rcv_pcl_bus); if (lynx->rcv_buffer) pci_free_consistent(lynx->pci_device, PAGE_SIZE, lynx->rcv_buffer, lynx->rcv_buffer_bus); iounmap(lynx->registers); kfree(lynx); fail_disable: pci_disable_device(dev); return ret; |
286468210 firewire: new dri... |
661 662 663 664 |
} static struct pci_device_id pci_table[] __devinitdata = { { |
b5e477290 firewire: nosy: m... |
665 666 667 668 |
.vendor = PCI_VENDOR_ID_TI, .device = PCI_DEVICE_ID_TI_PCILYNX, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, |
286468210 firewire: new dri... |
669 670 671 672 673 |
}, { } /* Terminating entry */ }; static struct pci_driver lynx_pci_driver = { |
b5e477290 firewire: nosy: m... |
674 |
.name = driver_name, |
286468210 firewire: new dri... |
675 676 |
.id_table = pci_table, .probe = add_card, |
b5e477290 firewire: nosy: m... |
677 |
.remove = remove_card, |
286468210 firewire: new dri... |
678 |
}; |
b5e477290 firewire: nosy: m... |
679 |
MODULE_AUTHOR("Kristian Hoegsberg"); |
286468210 firewire: new dri... |
680 681 682 683 684 685 |
MODULE_DESCRIPTION("Snoop mode driver for TI pcilynx 1394 controllers"); MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(pci, pci_table); static int __init nosy_init(void) { |
b5e477290 firewire: nosy: m... |
686 |
return pci_register_driver(&lynx_pci_driver); |
286468210 firewire: new dri... |
687 688 689 690 |
} static void __exit nosy_cleanup(void) { |
b5e477290 firewire: nosy: m... |
691 |
pci_unregister_driver(&lynx_pci_driver); |
286468210 firewire: new dri... |
692 |
|
7429b17d3 firewire: nosy: u... |
693 694 |
pr_info("Unloaded %s ", driver_name); |
286468210 firewire: new dri... |
695 |
} |
286468210 firewire: new dri... |
696 697 |
module_init(nosy_init); module_exit(nosy_cleanup); |