aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Richter <stefanr@s5r6.in-berlin.de>2010-07-27 04:26:33 -0400
committerStefan Richter <stefanr@s5r6.in-berlin.de>2010-07-27 05:04:10 -0400
commit286468210d83ce0ca1e37e346ed9f4457a161650 (patch)
treee445a09a6a074e3ae65479e417d41d4d1c41f571
parente40152ee1e1c7a63f4777791863215e3faa37a86 (diff)
firewire: new driver: nosy - IEEE 1394 traffic sniffer
This adds the traffic sniffer driver for Texas Instruments PCILynx/ PCILynx2 based cards. The use cases for nosy are analysis of nonstandard protocols and as an aid in development of drivers, applications, or firmwares. Author of the driver is Kristian Høgsberg. Known contributers are Jody McIntyre and Jonathan Woithe. Nosy programs PCILynx chips to operate in promiscuous mode, which is a feature that is not found in OHCI-1394 controllers. Hence, only special hardware as mentioned in the Kconfig help text is suitable for nosy. This is only the kernelspace part of nosy. There is a userspace interface to it, called nosy-dump, proposed to be added into the tools/ subdirectory of the kernel sources in a subsequent change. Kernelspace and userspave component of nosy communicate via a 'misc' character device file called /dev/nosy with a simple ioctl() and read() based protocol, as described by nosy-user.h. The files added here are taken from git://anongit.freedesktop.org/~krh/nosy commit ee29be97 (2009-11-10) with the following changes by Stefan Richter: - Kconfig and Makefile hunks are written from scratch. - Commented out version printk in nosy.c. - Included missing <linux/sched.h>, reported by Stephen Rothwell. "git shortlog nosy{-user.h,.c,.h}" from nosy's git repository: Jonathan Woithe (2): Nosy updates for recent kernels Fix uninitialised memory (needed for 2.6.31 kernel) Kristian Høgsberg (5): Pull over nosy from mercurial repo. Use a misc device instead. Add simple AV/C decoder. Don't break down on big payloads. Set parent device for misc device. As a low-level IEEE 1394 driver, its files are placed into drivers/firewire/ although nosy is not part of the firewire driver stack. I am aware of the following literature from Texas Instruments about PCILynx programming: SCPA020A - PCILynx 1394 to PCI Bus Interface TSB12LV21BPGF Functional Specification SLLA023 - Initialization and Asynchronous Programming of the TSB12LV21A 1394 Device Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de> Acked-by: Kristian Høgsberg <krh@bitplanet.net>
-rw-r--r--drivers/firewire/Kconfig23
-rw-r--r--drivers/firewire/Makefile1
-rw-r--r--drivers/firewire/nosy-user.h25
-rw-r--r--drivers/firewire/nosy.c695
-rw-r--r--drivers/firewire/nosy.h238
5 files changed, 982 insertions, 0 deletions
diff --git a/drivers/firewire/Kconfig b/drivers/firewire/Kconfig
index a9371b36a9b9..c4edc34d128b 100644
--- a/drivers/firewire/Kconfig
+++ b/drivers/firewire/Kconfig
@@ -66,4 +66,27 @@ config FIREWIRE_NET
66 66
67source "drivers/ieee1394/Kconfig" 67source "drivers/ieee1394/Kconfig"
68 68
69config FIREWIRE_NOSY
70 tristate "Nosy - a FireWire traffic sniffer for PCILynx cards"
71 depends on PCI
72 help
73 Nosy is an IEEE 1394 packet sniffer that is used for protocol
74 analysis and in development of IEEE 1394 drivers, applications,
75 or firmwares.
76
77 This driver lets you use a Texas Instruments PCILynx 1394 to PCI
78 link layer controller TSB12LV21/A/B as a low-budget bus analyzer.
79 PCILynx is a nowadays very rare IEEE 1394 controller which is
80 not OHCI 1394 compliant.
81
82 The following cards are known to be based on PCILynx or PCILynx-2:
83 IOI IOI-1394TT (PCI card), Unibrain Fireboard 400 PCI Lynx-2
84 (PCI card), Newer Technology FireWire 2 Go (CardBus card),
85 Apple Power Mac G3 blue & white (onboard controller).
86
87 To compile this driver as a module, say M here: The module will be
88 called nosy.
89
90 If unsure, say N.
91
69endmenu 92endmenu
diff --git a/drivers/firewire/Makefile b/drivers/firewire/Makefile
index a8f9bb6d9fdf..3c6a7fb20aa7 100644
--- a/drivers/firewire/Makefile
+++ b/drivers/firewire/Makefile
@@ -12,3 +12,4 @@ obj-$(CONFIG_FIREWIRE) += firewire-core.o
12obj-$(CONFIG_FIREWIRE_OHCI) += firewire-ohci.o 12obj-$(CONFIG_FIREWIRE_OHCI) += firewire-ohci.o
13obj-$(CONFIG_FIREWIRE_SBP2) += firewire-sbp2.o 13obj-$(CONFIG_FIREWIRE_SBP2) += firewire-sbp2.o
14obj-$(CONFIG_FIREWIRE_NET) += firewire-net.o 14obj-$(CONFIG_FIREWIRE_NET) += firewire-net.o
15obj-$(CONFIG_FIREWIRE_NOSY) += nosy.o
diff --git a/drivers/firewire/nosy-user.h b/drivers/firewire/nosy-user.h
new file mode 100644
index 000000000000..c9a1682ab45e
--- /dev/null
+++ b/drivers/firewire/nosy-user.h
@@ -0,0 +1,25 @@
1#ifndef __nosy_user_h
2#define __nosy_user_h
3
4#include <asm/ioctl.h>
5#include <asm/types.h>
6
7#define NOSY_IOC_GET_STATS _IOR('&', 0, struct nosy_stats)
8#define NOSY_IOC_START _IO('&', 1)
9#define NOSY_IOC_STOP _IO('&', 2)
10#define NOSY_IOC_FILTER _IOW('&', 2, __u32)
11
12struct nosy_stats {
13 __u32 total_packet_count;
14 __u32 lost_packet_count;
15};
16
17/*
18 * Format of packets returned from the kernel driver:
19 *
20 * quadlet with timestamp (microseconds)
21 * quadlet padded packet data...
22 * quadlet with ack
23 */
24
25#endif /* __nosy_user_h */
diff --git a/drivers/firewire/nosy.c b/drivers/firewire/nosy.c
new file mode 100644
index 000000000000..079710bf1197
--- /dev/null
+++ b/drivers/firewire/nosy.c
@@ -0,0 +1,695 @@
1/* -*- c-file-style: "linux" -*-
2 *
3 * nosy.c - Snoop mode driver for TI pcilynx 1394 controllers
4 * Copyright (C) 2002 Kristian Høgsberg
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 */
20
21#include <linux/kernel.h>
22#include <linux/slab.h>
23#include <linux/interrupt.h>
24#include <linux/sched.h> /* required for linux/wait.h */
25#include <linux/wait.h>
26#include <linux/errno.h>
27#include <linux/module.h>
28#include <linux/init.h>
29#include <linux/pci.h>
30#include <linux/fs.h>
31#include <linux/poll.h>
32#include <linux/miscdevice.h>
33#include <asm/byteorder.h>
34#include <asm/atomic.h>
35#include <asm/io.h>
36#include <asm/uaccess.h>
37#include <asm/timex.h>
38
39#include "nosy.h"
40#include "nosy-user.h"
41
42#define TCODE_PHY_PACKET 0x10
43#define PCI_DEVICE_ID_TI_PCILYNX 0x8000
44
45#define notify(s, args...) printk(KERN_NOTICE s, ## args)
46#define error(s, args...) printk(KERN_ERR s, ## args)
47#define debug(s, args...) printk(KERN_DEBUG s, ## args)
48
49static const char driver_name[] = "nosy";
50
51struct pcl_status {
52 unsigned int transfer_count : 13;
53 unsigned int reserved0 : 1;
54 unsigned int ack_type : 1;
55 unsigned int ack : 4;
56 unsigned int rcv_speed : 2;
57 unsigned int rcv_dma_channel : 6;
58 unsigned int packet_complete : 1;
59 unsigned int packet_error : 1;
60 unsigned int master_error : 1;
61 unsigned int iso_mode : 1;
62 unsigned int self_id : 1;
63};
64
65/* this is the physical layout of a PCL, its size is 128 bytes */
66struct pcl {
67 u32 next;
68 u32 async_error_next;
69 u32 user_data;
70 struct pcl_status pcl_status;
71 u32 remaining_transfer_count;
72 u32 next_data_buffer;
73 struct {
74 u32 control;
75 u32 pointer;
76 } buffer[13] __attribute__ ((packed));
77} __attribute__ ((packed));
78
79struct packet {
80 unsigned int length : 16;
81 unsigned int code : 16;
82 char data[0];
83};
84
85struct packet_buffer {
86 char *data;
87 size_t capacity;
88 long total_packet_count, lost_packet_count;
89 atomic_t size;
90 struct packet *head, *tail;
91 wait_queue_head_t wait;
92};
93
94struct pcilynx {
95 struct pci_dev *pci_device;
96 unsigned char *registers;
97
98 struct pcl *rcv_start_pcl, *rcv_pcl;
99 u32 *rcv_buffer;
100
101 dma_addr_t rcv_start_pcl_bus, rcv_pcl_bus, rcv_buffer_bus;
102
103 spinlock_t client_list_lock;
104 struct list_head client_list;
105
106 struct miscdevice misc;
107};
108
109
110struct client {
111 struct pcilynx *lynx;
112 unsigned long tcode_mask;
113 struct packet_buffer buffer;
114 struct list_head link;
115};
116
117#define MAX_MINORS 64
118struct pcilynx *minors[MAX_MINORS];
119
120static int
121packet_buffer_init(struct packet_buffer *buffer, size_t capacity)
122{
123 buffer->data = kmalloc(capacity, GFP_KERNEL);
124 if (buffer->data == NULL)
125 return -ENOMEM;
126 buffer->head = (struct packet *) buffer->data;
127 buffer->tail = (struct packet *) buffer->data;
128 buffer->capacity = capacity;
129 buffer->lost_packet_count = 0;
130 atomic_set(&buffer->size, 0);
131 init_waitqueue_head(&buffer->wait);
132
133 return 0;
134}
135
136static void
137packet_buffer_destroy(struct packet_buffer *buffer)
138{
139 kfree(buffer->data);
140}
141
142static int
143packet_buffer_get(struct packet_buffer *buffer, void *data, size_t user_length)
144{
145 size_t length;
146 char *end;
147
148 if (wait_event_interruptible(buffer->wait,
149 atomic_read(&buffer->size) > 0))
150 return -ERESTARTSYS;
151
152 /* FIXME: Check length <= user_length. */
153
154 end = buffer->data + buffer->capacity;
155 length = buffer->head->length;
156
157 if (&buffer->head->data[length] < end) {
158 if (copy_to_user(data, buffer->head->data, length))
159 return -EFAULT;
160 buffer->head = (struct packet *) &buffer->head->data[length];
161 }
162 else {
163 size_t split = end - buffer->head->data;
164
165 if (copy_to_user(data, buffer->head->data, split))
166 return -EFAULT;
167 if (copy_to_user(data + split, buffer->data, length - split))
168 return -EFAULT;
169 buffer->head = (struct packet *) &buffer->data[length - split];
170 }
171
172 /* Decrease buffer->size as the last thing, since this is what
173 * keeps the interrupt from overwriting the packet we are
174 * retrieving from the buffer. */
175
176 atomic_sub(sizeof (struct packet) + length, &buffer->size);
177
178 return length;
179}
180
181static void
182packet_buffer_put(struct packet_buffer *buffer, void *data, size_t length)
183{
184 char *end;
185
186 buffer->total_packet_count++;
187
188 if (buffer->capacity <
189 atomic_read(&buffer->size) + sizeof (struct packet) + length) {
190 buffer->lost_packet_count++;
191 return;
192 }
193
194 end = buffer->data + buffer->capacity;
195 buffer->tail->length = length;
196
197 if (&buffer->tail->data[length] < end) {
198 memcpy(buffer->tail->data, data, length);
199 buffer->tail = (struct packet *) &buffer->tail->data[length];
200 }
201 else {
202 size_t split = end - buffer->tail->data;
203
204 memcpy(buffer->tail->data, data, split);
205 memcpy(buffer->data, data + split, length - split);
206 buffer->tail = (struct packet *) &buffer->data[length - split];
207 }
208
209 /* Finally, adjust buffer size and wake up userspace reader. */
210
211 atomic_add(sizeof (struct packet) + length, &buffer->size);
212 wake_up_interruptible(&buffer->wait);
213}
214
215static inline void
216reg_write(struct pcilynx *lynx, int offset, u32 data)
217{
218 writel(data, lynx->registers + offset);
219}
220
221static inline u32
222reg_read(struct pcilynx *lynx, int offset)
223{
224 return readl(lynx->registers + offset);
225}
226
227static inline void
228reg_set_bits(struct pcilynx *lynx, int offset, u32 mask)
229{
230 reg_write(lynx, offset, (reg_read(lynx, offset) | mask));
231}
232
233/* Maybe the pcl programs could be setup to just append data instead
234 * of using a whole packet. */
235
236static inline void
237run_pcl(struct pcilynx *lynx, dma_addr_t pcl_bus, int dmachan)
238{
239 reg_write(lynx, DMA0_CURRENT_PCL + dmachan * 0x20, pcl_bus);
240 reg_write(lynx, DMA0_CHAN_CTRL + dmachan * 0x20,
241 DMA_CHAN_CTRL_ENABLE | DMA_CHAN_CTRL_LINK);
242}
243
244static int
245set_phy_reg(struct pcilynx *lynx, int addr, int val)
246{
247 if (addr > 15) {
248 debug("%s: PHY register address %d out of range",
249 __FUNCTION__, addr);
250 return -1;
251 }
252
253 if (val > 0xff) {
254 debug("%s: PHY register value %d out of range",
255 __FUNCTION__, val);
256 return -1;
257 }
258
259 reg_write(lynx, LINK_PHY, LINK_PHY_WRITE |
260 LINK_PHY_ADDR(addr) | LINK_PHY_WDATA(val));
261
262 return 0;
263}
264
265static void
266nosy_start_snoop(struct client *client)
267{
268 unsigned long flags;
269
270 spin_lock_irqsave(&client->lynx->client_list_lock, flags);
271 list_add_tail(&client->link, &client->lynx->client_list);
272 spin_unlock_irqrestore(&client->lynx->client_list_lock, flags);
273}
274
275static void
276nosy_stop_snoop(struct client *client)
277{
278 unsigned long flags;
279
280 spin_lock_irqsave(&client->lynx->client_list_lock, flags);
281 list_del(&client->link);
282 spin_unlock_irqrestore(&client->lynx->client_list_lock, flags);
283}
284
285static struct client *
286nosy_add_client(struct pcilynx *lynx)
287{
288 struct client *client;
289
290 client = kmalloc(sizeof *client, GFP_KERNEL);
291 client->tcode_mask = ~0;
292 client->lynx = lynx;
293 INIT_LIST_HEAD(&client->link);
294
295 if (packet_buffer_init(&client->buffer, 128 * 1024) < 0) {
296 kfree(client);
297 debug("Failed to allocate packet buffer\n");
298 return NULL;
299 }
300
301 return client;
302}
303
304static void
305nosy_remove_client(struct client *client)
306{
307 nosy_stop_snoop(client);
308 packet_buffer_destroy(&client->buffer);
309 kfree(client);
310}
311
312static int
313nosy_open(struct inode *inode, struct file *file)
314{
315 int minor = iminor(inode);
316
317 if (minor > MAX_MINORS || minors[minor] == NULL)
318 return -ENODEV;
319
320 file->private_data = nosy_add_client(minors[minor]);
321 if (file->private_data == NULL)
322 return -ENOMEM;
323 else
324 return 0;
325}
326
327static int
328nosy_release(struct inode *inode, struct file *file)
329{
330 nosy_remove_client(file->private_data);
331
332 return 0;
333}
334
335static unsigned int
336nosy_poll(struct file *file, poll_table *pt)
337{
338 struct client *client = file->private_data;
339
340 poll_wait(file, &client->buffer.wait, pt);
341
342 if (atomic_read(&client->buffer.size) > 0)
343 return POLLIN | POLLRDNORM;
344 else
345 return 0;
346}
347
348static ssize_t
349nosy_read(struct file *file, char *buffer, size_t count, loff_t *offset)
350{
351 struct client *client = file->private_data;
352
353 return packet_buffer_get(&client->buffer, buffer, count);
354}
355
356static int
357nosy_ioctl(struct inode *inode, struct file *file,
358 unsigned int cmd, unsigned long arg)
359{
360 struct client *client = file->private_data;
361
362 switch (cmd) {
363 case NOSY_IOC_GET_STATS: {
364 struct nosy_stats stats;
365
366 stats.total_packet_count = client->buffer.total_packet_count;
367 stats.lost_packet_count = client->buffer.lost_packet_count;
368 if (copy_to_user((void *) arg, &stats, sizeof stats))
369 return -EFAULT;
370 else
371 return 0;
372 }
373
374 case NOSY_IOC_START:
375 nosy_start_snoop(client);
376 return 0;
377
378 case NOSY_IOC_STOP:
379 nosy_stop_snoop(client);
380 return 0;
381
382 case NOSY_IOC_FILTER:
383 client->tcode_mask = arg;
384 return 0;
385
386 default:
387 return -EINVAL;
388 /* Flush buffer, configure filter. */
389 }
390}
391
392static struct file_operations nosy_ops = {
393 .owner = THIS_MODULE,
394 .read = nosy_read,
395 .ioctl = nosy_ioctl,
396 .poll = nosy_poll,
397 .open = nosy_open,
398 .release = nosy_release,
399};
400
401#define PHY_PACKET_SIZE 12 /* 1 payload, 1 inverse, 1 ack = 3 quadlets */
402
403struct link_packet {
404 unsigned int priority : 4;
405 unsigned int tcode : 4;
406 unsigned int rt : 2;
407 unsigned int tlabel : 6;
408 unsigned int destination : 16;
409};
410
411static void
412packet_handler(struct pcilynx *lynx)
413{
414 unsigned long flags;
415 struct list_head *pos;
416 struct client *client;
417 unsigned long tcode_mask;
418 size_t length;
419 struct link_packet *packet;
420 struct timeval tv;
421
422 /* FIXME: Also report rcv_speed. */
423
424 length = lynx->rcv_pcl->pcl_status.transfer_count;
425 packet = (struct link_packet *) &lynx->rcv_buffer[1];
426
427 do_gettimeofday(&tv);
428 lynx->rcv_buffer[0] = tv.tv_usec;
429
430 if (length == PHY_PACKET_SIZE)
431 tcode_mask = 1 << TCODE_PHY_PACKET;
432 else
433 tcode_mask = 1 << packet->tcode;
434
435 spin_lock_irqsave(&lynx->client_list_lock, flags);
436
437 list_for_each(pos, &lynx->client_list) {
438 client = list_entry(pos, struct client, link);
439 if (client->tcode_mask & tcode_mask)
440 packet_buffer_put(&client->buffer,
441 lynx->rcv_buffer, length + 4);
442 }
443
444 spin_unlock_irqrestore(&lynx->client_list_lock, flags);
445}
446
447static void
448bus_reset_handler(struct pcilynx *lynx)
449{
450 unsigned long flags;
451 struct list_head *pos;
452 struct client *client;
453 struct timeval tv;
454
455 do_gettimeofday(&tv);
456
457 spin_lock_irqsave(&lynx->client_list_lock, flags);
458
459 list_for_each(pos, &lynx->client_list) {
460 client = list_entry(pos, struct client, link);
461 packet_buffer_put(&client->buffer, &tv.tv_usec, 4);
462 }
463
464 spin_unlock_irqrestore(&lynx->client_list_lock, flags);
465}
466
467
468
469static irqreturn_t
470irq_handler(int irq, void *device)
471{
472 struct pcilynx *lynx = (struct pcilynx *) device;
473 u32 pci_int_status;
474
475 pci_int_status = reg_read(lynx, PCI_INT_STATUS);
476
477 if ((pci_int_status & PCI_INT_INT_PEND) == 0)
478 /* Not our interrupt, bail out quickly. */
479 return IRQ_NONE;
480
481 if ((pci_int_status & PCI_INT_P1394_INT) != 0) {
482 u32 link_int_status;
483
484 link_int_status = reg_read(lynx, LINK_INT_STATUS);
485 reg_write(lynx, LINK_INT_STATUS, link_int_status);
486
487 if ((link_int_status & LINK_INT_PHY_BUSRESET) > 0)
488 bus_reset_handler(lynx);
489 }
490
491 /* Clear the PCI_INT_STATUS register only after clearing the
492 * LINK_INT_STATUS register; otherwise the PCI_INT_P1394 will
493 * be set again immediately. */
494
495 reg_write(lynx, PCI_INT_STATUS, pci_int_status);
496
497 if ((pci_int_status & PCI_INT_DMA0_HLT) > 0) {
498 packet_handler(lynx);
499 run_pcl(lynx, lynx->rcv_start_pcl_bus, 0);
500 }
501
502 return IRQ_HANDLED;
503}
504
505static void
506remove_card(struct pci_dev *dev)
507{
508 struct pcilynx *lynx;
509
510 lynx = pci_get_drvdata(dev);
511 if (!lynx)
512 return;
513 pci_set_drvdata(dev, NULL);
514
515 reg_write(lynx, PCI_INT_ENABLE, 0);
516 free_irq(lynx->pci_device->irq, lynx);
517
518 pci_free_consistent(lynx->pci_device, sizeof (struct pcl),
519 lynx->rcv_start_pcl, lynx->rcv_start_pcl_bus);
520 pci_free_consistent(lynx->pci_device, sizeof (struct pcl),
521 lynx->rcv_pcl, lynx->rcv_pcl_bus);
522 pci_free_consistent(lynx->pci_device, PAGE_SIZE,
523 lynx->rcv_buffer, lynx->rcv_buffer_bus);
524
525 iounmap(lynx->registers);
526
527 minors[lynx->misc.minor] = NULL;
528 misc_deregister(&lynx->misc);
529
530 kfree(lynx);
531}
532
533#define RCV_BUFFER_SIZE (16 * 1024)
534
535#define FAIL(s, args...) \
536 do { \
537 error(s, ## args); \
538 return err; \
539 } while (0)
540
541static int __devinit
542add_card(struct pci_dev *dev, const struct pci_device_id *unused)
543{
544 struct pcilynx *lynx;
545 u32 p, end;
546 int err, i;
547
548 err = -ENXIO;
549
550 if (pci_set_dma_mask(dev, 0xffffffff))
551 FAIL("DMA address limits not supported "
552 "for PCILynx hardware.\n");
553 if (pci_enable_device(dev))
554 FAIL("Failed to enable PCILynx hardware.\n");
555 pci_set_master(dev);
556
557 err = -ENOMEM;
558
559 lynx = kzalloc(sizeof *lynx, GFP_KERNEL);
560 if (lynx == NULL)
561 FAIL("Failed to allocate control structure memory.\n");
562
563 lynx->pci_device = dev;
564 pci_set_drvdata(dev, lynx);
565
566 spin_lock_init(&lynx->client_list_lock);
567 INIT_LIST_HEAD(&lynx->client_list);
568
569 lynx->registers = ioremap_nocache(pci_resource_start(dev, 0),
570 PCILYNX_MAX_REGISTER);
571
572 lynx->rcv_start_pcl = pci_alloc_consistent(lynx->pci_device,
573 sizeof(struct pcl),
574 &lynx->rcv_start_pcl_bus);
575 lynx->rcv_pcl = pci_alloc_consistent(lynx->pci_device,
576 sizeof(struct pcl),
577 &lynx->rcv_pcl_bus);
578 lynx->rcv_buffer = pci_alloc_consistent(lynx->pci_device, RCV_BUFFER_SIZE,
579 &lynx->rcv_buffer_bus);
580 if (lynx->rcv_start_pcl == NULL ||
581 lynx->rcv_pcl == NULL ||
582 lynx->rcv_buffer == NULL)
583 /* FIXME: do proper error handling. */
584 FAIL("Failed to allocate receive buffer.\n");
585
586 lynx->rcv_start_pcl->next = lynx->rcv_pcl_bus;
587 lynx->rcv_pcl->next = PCL_NEXT_INVALID;
588 lynx->rcv_pcl->async_error_next = PCL_NEXT_INVALID;
589
590 lynx->rcv_pcl->buffer[0].control =
591 PCL_CMD_RCV | PCL_BIGENDIAN | 2044;
592 lynx->rcv_pcl->buffer[0].pointer = lynx->rcv_buffer_bus + 4;
593 p = lynx->rcv_buffer_bus + 2048;
594 end = lynx->rcv_buffer_bus + RCV_BUFFER_SIZE;
595 for (i = 1; p < end; i++, p += 2048) {
596 lynx->rcv_pcl->buffer[i].control =
597 PCL_CMD_RCV | PCL_BIGENDIAN | 2048;
598 lynx->rcv_pcl->buffer[i].pointer = p;
599 }
600 lynx->rcv_pcl->buffer[i - 1].control |= PCL_LAST_BUFF;
601
602 reg_set_bits(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET);
603 /* Fix buggy cards with autoboot pin not tied low: */
604 reg_write(lynx, DMA0_CHAN_CTRL, 0);
605 reg_write(lynx, DMA_GLOBAL_REGISTER, 0x00 << 24);
606
607#if 0
608 /* now, looking for PHY register set */
609 if ((get_phy_reg(lynx, 2) & 0xe0) == 0xe0) {
610 lynx->phyic.reg_1394a = 1;
611 PRINT(KERN_INFO, lynx->id,
612 "found 1394a conform PHY (using extended register set)");
613 lynx->phyic.vendor = get_phy_vendorid(lynx);
614 lynx->phyic.product = get_phy_productid(lynx);
615 } else {
616 lynx->phyic.reg_1394a = 0;
617 PRINT(KERN_INFO, lynx->id, "found old 1394 PHY");
618 }
619#endif
620
621 /* Setup the general receive FIFO max size. */
622 reg_write(lynx, FIFO_SIZES, 255);
623
624 reg_set_bits(lynx, PCI_INT_ENABLE, PCI_INT_DMA_ALL);
625
626 reg_write(lynx, LINK_INT_ENABLE,
627 LINK_INT_PHY_TIME_OUT | LINK_INT_PHY_REG_RCVD |
628 LINK_INT_PHY_BUSRESET | LINK_INT_IT_STUCK |
629 LINK_INT_AT_STUCK | LINK_INT_SNTRJ |
630 LINK_INT_TC_ERR | LINK_INT_GRF_OVER_FLOW |
631 LINK_INT_ITF_UNDER_FLOW | LINK_INT_ATF_UNDER_FLOW);
632
633 /* Disable the L flag in self ID packets. */
634 set_phy_reg(lynx, 4, 0);
635
636 /* Put this baby into snoop mode */
637 reg_set_bits(lynx, LINK_CONTROL, LINK_CONTROL_SNOOP_ENABLE);
638
639 run_pcl(lynx, lynx->rcv_start_pcl_bus, 0);
640
641 if (request_irq(dev->irq, irq_handler, IRQF_SHARED, driver_name, lynx))
642 FAIL("Failed to allocate shared interrupt %d.", dev->irq);
643
644 lynx->misc.parent = &dev->dev;
645 lynx->misc.minor = MISC_DYNAMIC_MINOR;
646 lynx->misc.name = "nosy";
647 lynx->misc.fops = &nosy_ops;
648 if (misc_register(&lynx->misc))
649 FAIL("Failed to register misc char device.");
650 minors[lynx->misc.minor] = lynx;
651
652 notify("Initialized PCILynx IEEE1394 card, irq=%d\n", dev->irq);
653
654 return 0;
655}
656
657static struct pci_device_id pci_table[] __devinitdata = {
658 {
659 .vendor = PCI_VENDOR_ID_TI,
660 .device = PCI_DEVICE_ID_TI_PCILYNX,
661 .subvendor = PCI_ANY_ID,
662 .subdevice = PCI_ANY_ID,
663 },
664 { } /* Terminating entry */
665};
666
667static struct pci_driver lynx_pci_driver = {
668 .name = (char *) driver_name,
669 .id_table = pci_table,
670 .probe = add_card,
671 .remove = __devexit_p(remove_card),
672};
673
674MODULE_AUTHOR("Kristian Høgsberg");
675MODULE_DESCRIPTION("Snoop mode driver for TI pcilynx 1394 controllers");
676MODULE_LICENSE("GPL");
677MODULE_DEVICE_TABLE(pci, pci_table);
678
679static int __init nosy_init(void)
680{
681 /* notify("Loaded %s version %s.\n", driver_name, VERSION); */
682
683 return pci_register_driver(&lynx_pci_driver);
684}
685
686static void __exit nosy_cleanup(void)
687{
688 pci_unregister_driver(&lynx_pci_driver);
689
690 notify("Unloaded %s.\n", driver_name);
691}
692
693
694module_init(nosy_init);
695module_exit(nosy_cleanup);
diff --git a/drivers/firewire/nosy.h b/drivers/firewire/nosy.h
new file mode 100644
index 000000000000..3440071ac0d2
--- /dev/null
+++ b/drivers/firewire/nosy.h
@@ -0,0 +1,238 @@
1/* Chip register definitions for PCILynx chipset. Based on pcilynx.h
2 * from the Linux 1394 drivers, but modified a bit so the names here
3 * match the specification exactly (even though they have weird names,
4 * like xxx_OVER_FLOW, or arbitrary abbreviations like SNTRJ for "sent
5 * reject" etc.)
6 */
7
8#define PCILYNX_MAX_REGISTER 0xfff
9#define PCILYNX_MAX_MEMORY 0xffff
10
11#define PCI_LATENCY_CACHELINE 0x0c
12
13#define MISC_CONTROL 0x40
14#define MISC_CONTROL_SWRESET (1<<0)
15
16#define SERIAL_EEPROM_CONTROL 0x44
17
18#define PCI_INT_STATUS 0x48
19#define PCI_INT_ENABLE 0x4c
20/* status and enable have identical bit numbers */
21#define PCI_INT_INT_PEND (1<<31)
22#define PCI_INT_FRC_INT (1<<30)
23#define PCI_INT_SLV_ADR_PERR (1<<28)
24#define PCI_INT_SLV_DAT_PERR (1<<27)
25#define PCI_INT_MST_DAT_PERR (1<<26)
26#define PCI_INT_MST_DEV_TO (1<<25)
27#define PCI_INT_INT_SLV_TO (1<<23)
28#define PCI_INT_AUX_TO (1<<18)
29#define PCI_INT_AUX_INT (1<<17)
30#define PCI_INT_P1394_INT (1<<16)
31#define PCI_INT_DMA4_PCL (1<<9)
32#define PCI_INT_DMA4_HLT (1<<8)
33#define PCI_INT_DMA3_PCL (1<<7)
34#define PCI_INT_DMA3_HLT (1<<6)
35#define PCI_INT_DMA2_PCL (1<<5)
36#define PCI_INT_DMA2_HLT (1<<4)
37#define PCI_INT_DMA1_PCL (1<<3)
38#define PCI_INT_DMA1_HLT (1<<2)
39#define PCI_INT_DMA0_PCL (1<<1)
40#define PCI_INT_DMA0_HLT (1<<0)
41/* all DMA interrupts combined: */
42#define PCI_INT_DMA_ALL 0x3ff
43
44#define PCI_INT_DMA_HLT(chan) (1 << (chan * 2))
45#define PCI_INT_DMA_PCL(chan) (1 << (chan * 2 + 1))
46
47#define LBUS_ADDR 0xb4
48#define LBUS_ADDR_SEL_RAM (0x0<<16)
49#define LBUS_ADDR_SEL_ROM (0x1<<16)
50#define LBUS_ADDR_SEL_AUX (0x2<<16)
51#define LBUS_ADDR_SEL_ZV (0x3<<16)
52
53#define GPIO_CTRL_A 0xb8
54#define GPIO_CTRL_B 0xbc
55#define GPIO_DATA_BASE 0xc0
56
57#define DMA_BREG(base, chan) (base + chan * 0x20)
58#define DMA_SREG(base, chan) (base + chan * 0x10)
59
60#define PCL_NEXT_INVALID (1<<0)
61
62/* transfer commands */
63#define PCL_CMD_RCV (0x1<<24)
64#define PCL_CMD_RCV_AND_UPDATE (0xa<<24)
65#define PCL_CMD_XMT (0x2<<24)
66#define PCL_CMD_UNFXMT (0xc<<24)
67#define PCL_CMD_PCI_TO_LBUS (0x8<<24)
68#define PCL_CMD_LBUS_TO_PCI (0x9<<24)
69
70/* aux commands */
71#define PCL_CMD_NOP (0x0<<24)
72#define PCL_CMD_LOAD (0x3<<24)
73#define PCL_CMD_STOREQ (0x4<<24)
74#define PCL_CMD_STORED (0xb<<24)
75#define PCL_CMD_STORE0 (0x5<<24)
76#define PCL_CMD_STORE1 (0x6<<24)
77#define PCL_CMD_COMPARE (0xe<<24)
78#define PCL_CMD_SWAP_COMPARE (0xf<<24)
79#define PCL_CMD_ADD (0xd<<24)
80#define PCL_CMD_BRANCH (0x7<<24)
81
82/* BRANCH condition codes */
83#define PCL_COND_DMARDY_SET (0x1<<20)
84#define PCL_COND_DMARDY_CLEAR (0x2<<20)
85
86#define PCL_GEN_INTR (1<<19)
87#define PCL_LAST_BUFF (1<<18)
88#define PCL_LAST_CMD (PCL_LAST_BUFF)
89#define PCL_WAITSTAT (1<<17)
90#define PCL_BIGENDIAN (1<<16)
91#define PCL_ISOMODE (1<<12)
92
93#define DMA0_PREV_PCL 0x100
94#define DMA1_PREV_PCL 0x120
95#define DMA2_PREV_PCL 0x140
96#define DMA3_PREV_PCL 0x160
97#define DMA4_PREV_PCL 0x180
98#define DMA_PREV_PCL(chan) (DMA_BREG(DMA0_PREV_PCL, chan))
99
100#define DMA0_CURRENT_PCL 0x104
101#define DMA1_CURRENT_PCL 0x124
102#define DMA2_CURRENT_PCL 0x144
103#define DMA3_CURRENT_PCL 0x164
104#define DMA4_CURRENT_PCL 0x184
105#define DMA_CURRENT_PCL(chan) (DMA_BREG(DMA0_CURRENT_PCL, chan))
106
107#define DMA0_CHAN_STAT 0x10c
108#define DMA1_CHAN_STAT 0x12c
109#define DMA2_CHAN_STAT 0x14c
110#define DMA3_CHAN_STAT 0x16c
111#define DMA4_CHAN_STAT 0x18c
112#define DMA_CHAN_STAT(chan) (DMA_BREG(DMA0_CHAN_STAT, chan))
113/* CHAN_STATUS registers share bits */
114#define DMA_CHAN_STAT_SELFID (1<<31)
115#define DMA_CHAN_STAT_ISOPKT (1<<30)
116#define DMA_CHAN_STAT_PCIERR (1<<29)
117#define DMA_CHAN_STAT_PKTERR (1<<28)
118#define DMA_CHAN_STAT_PKTCMPL (1<<27)
119#define DMA_CHAN_STAT_SPECIALACK (1<<14)
120
121
122#define DMA0_CHAN_CTRL 0x110
123#define DMA1_CHAN_CTRL 0x130
124#define DMA2_CHAN_CTRL 0x150
125#define DMA3_CHAN_CTRL 0x170
126#define DMA4_CHAN_CTRL 0x190
127#define DMA_CHAN_CTRL(chan) (DMA_BREG(DMA0_CHAN_CTRL, chan))
128/* CHAN_CTRL registers share bits */
129#define DMA_CHAN_CTRL_ENABLE (1<<31)
130#define DMA_CHAN_CTRL_BUSY (1<<30)
131#define DMA_CHAN_CTRL_LINK (1<<29)
132
133#define DMA0_READY 0x114
134#define DMA1_READY 0x134
135#define DMA2_READY 0x154
136#define DMA3_READY 0x174
137#define DMA4_READY 0x194
138#define DMA_READY(chan) (DMA_BREG(DMA0_READY, chan))
139
140#define DMA_GLOBAL_REGISTER 0x908
141
142#define FIFO_SIZES 0xa00
143
144#define FIFO_CONTROL 0xa10
145#define FIFO_CONTROL_GRF_FLUSH (1<<4)
146#define FIFO_CONTROL_ITF_FLUSH (1<<3)
147#define FIFO_CONTROL_ATF_FLUSH (1<<2)
148
149#define FIFO_XMIT_THRESHOLD 0xa14
150
151#define DMA0_WORD0_CMP_VALUE 0xb00
152#define DMA1_WORD0_CMP_VALUE 0xb10
153#define DMA2_WORD0_CMP_VALUE 0xb20
154#define DMA3_WORD0_CMP_VALUE 0xb30
155#define DMA4_WORD0_CMP_VALUE 0xb40
156#define DMA_WORD0_CMP_VALUE(chan) (DMA_SREG(DMA0_WORD0_CMP_VALUE, chan))
157
158#define DMA0_WORD0_CMP_ENABLE 0xb04
159#define DMA1_WORD0_CMP_ENABLE 0xb14
160#define DMA2_WORD0_CMP_ENABLE 0xb24
161#define DMA3_WORD0_CMP_ENABLE 0xb34
162#define DMA4_WORD0_CMP_ENABLE 0xb44
163#define DMA_WORD0_CMP_ENABLE(chan) (DMA_SREG(DMA0_WORD0_CMP_ENABLE,chan))
164
165#define DMA0_WORD1_CMP_VALUE 0xb08
166#define DMA1_WORD1_CMP_VALUE 0xb18
167#define DMA2_WORD1_CMP_VALUE 0xb28
168#define DMA3_WORD1_CMP_VALUE 0xb38
169#define DMA4_WORD1_CMP_VALUE 0xb48
170#define DMA_WORD1_CMP_VALUE(chan) (DMA_SREG(DMA0_WORD1_CMP_VALUE, chan))
171
172#define DMA0_WORD1_CMP_ENABLE 0xb0c
173#define DMA1_WORD1_CMP_ENABLE 0xb1c
174#define DMA2_WORD1_CMP_ENABLE 0xb2c
175#define DMA3_WORD1_CMP_ENABLE 0xb3c
176#define DMA4_WORD1_CMP_ENABLE 0xb4c
177#define DMA_WORD1_CMP_ENABLE(chan) (DMA_SREG(DMA0_WORD1_CMP_ENABLE,chan))
178/* word 1 compare enable flags */
179#define DMA_WORD1_CMP_MATCH_OTHERBUS (1<<15)
180#define DMA_WORD1_CMP_MATCH_BROADCAST (1<<14)
181#define DMA_WORD1_CMP_MATCH_BUS_BCAST (1<<13)
182#define DMA_WORD1_CMP_MATCH_LOCAL_NODE (1<<12)
183#define DMA_WORD1_CMP_MATCH_EXACT (1<<11)
184#define DMA_WORD1_CMP_ENABLE_SELF_ID (1<<10)
185#define DMA_WORD1_CMP_ENABLE_MASTER (1<<8)
186
187#define LINK_ID 0xf00
188#define LINK_ID_BUS(id) (id<<22)
189#define LINK_ID_NODE(id) (id<<16)
190
191#define LINK_CONTROL 0xf04
192#define LINK_CONTROL_BUSY (1<<29)
193#define LINK_CONTROL_TX_ISO_EN (1<<26)
194#define LINK_CONTROL_RX_ISO_EN (1<<25)
195#define LINK_CONTROL_TX_ASYNC_EN (1<<24)
196#define LINK_CONTROL_RX_ASYNC_EN (1<<23)
197#define LINK_CONTROL_RESET_TX (1<<21)
198#define LINK_CONTROL_RESET_RX (1<<20)
199#define LINK_CONTROL_CYCMASTER (1<<11)
200#define LINK_CONTROL_CYCSOURCE (1<<10)
201#define LINK_CONTROL_CYCTIMEREN (1<<9)
202#define LINK_CONTROL_RCV_CMP_VALID (1<<7)
203#define LINK_CONTROL_SNOOP_ENABLE (1<<6)
204
205#define CYCLE_TIMER 0xf08
206
207#define LINK_PHY 0xf0c
208#define LINK_PHY_READ (1<<31)
209#define LINK_PHY_WRITE (1<<30)
210#define LINK_PHY_ADDR(addr) (addr<<24)
211#define LINK_PHY_WDATA(data) (data<<16)
212#define LINK_PHY_RADDR(addr) (addr<<8)
213
214
215#define LINK_INT_STATUS 0xf14
216#define LINK_INT_ENABLE 0xf18
217/* status and enable have identical bit numbers */
218#define LINK_INT_LINK_INT (1<<31)
219#define LINK_INT_PHY_TIME_OUT (1<<30)
220#define LINK_INT_PHY_REG_RCVD (1<<29)
221#define LINK_INT_PHY_BUSRESET (1<<28)
222#define LINK_INT_TX_RDY (1<<26)
223#define LINK_INT_RX_DATA_RDY (1<<25)
224#define LINK_INT_IT_STUCK (1<<20)
225#define LINK_INT_AT_STUCK (1<<19)
226#define LINK_INT_SNTRJ (1<<17)
227#define LINK_INT_HDR_ERR (1<<16)
228#define LINK_INT_TC_ERR (1<<15)
229#define LINK_INT_CYC_SEC (1<<11)
230#define LINK_INT_CYC_STRT (1<<10)
231#define LINK_INT_CYC_DONE (1<<9)
232#define LINK_INT_CYC_PEND (1<<8)
233#define LINK_INT_CYC_LOST (1<<7)
234#define LINK_INT_CYC_ARB_FAILED (1<<6)
235#define LINK_INT_GRF_OVER_FLOW (1<<5)
236#define LINK_INT_ITF_UNDER_FLOW (1<<4)
237#define LINK_INT_ATF_UNDER_FLOW (1<<3)
238#define LINK_INT_IARB_FAILED (1<<0)