1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
// SPDX-License-Identifier: GPL-2.0-only

/*
 *	Hardware driver for NI Mite PCI interface chip,
 *	adapted from COMEDI
 *
 *	Copyright (C) 1997-8 David A. Schleef
 *	Copyright (C) 2002 Frank Mori Hess
 *
 *	The PCI-MIO E series driver was originally written by
 *	Tomasz Motylewski <...>, and ported to comedi by ds.
 *
 *	References for specifications:
 *
 *	   321747b.pdf  Register Level Programmer Manual (obsolete)
 *	   321747c.pdf  Register Level Programmer Manual (new)
 *	   DAQ-STC reference manual
 *
 *	Other possibly relevant info:
 *
 *	   320517c.pdf  User manual (obsolete)
 *	   320517f.pdf  User manual (new)
 *	   320889a.pdf  delete
 *	   320906c.pdf  maximum signal ratings
 *	   321066a.pdf  about 16x
 *	   321791a.pdf  discontinuation of at-mio-16e-10 rev. c
 *	   321808a.pdf  about at-mio-16e-10 rev P
 *	   321837a.pdf  discontinuation of at-mio-16de-10 rev d
 *	   321838a.pdf  about at-mio-16de-10 rev N
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/io.h>
#include <linux/slab.h>

#include "mite.h"

#define PCI_MITE_SIZE		4096
#define PCI_DAQ_SIZE		4096

struct mite_struct *mite_devices;

#define TOP_OF_PAGE(x) ((x) | (~(PAGE_MASK)))

void mite_init(void)
{
	struct pci_dev *pcidev;
	struct mite_struct *mite;

	for (pcidev = pci_get_device(PCI_VENDOR_ID_NATINST, PCI_ANY_ID, NULL);
		pcidev;
		pcidev = pci_get_device(PCI_VENDOR_ID_NATINST, PCI_ANY_ID, pcidev)) {
		mite = kzalloc(sizeof(*mite), GFP_KERNEL);
		if (!mite)
			return;

		mite->pcidev = pcidev;
		pci_dev_get(mite->pcidev);
		mite->next = mite_devices;
		mite_devices = mite;
	}
}

int mite_setup(struct mite_struct *mite)
{
	u32 addr;

	if (pci_enable_device(mite->pcidev)) {
		pr_err("mite: error enabling mite.\n");
		return -EIO;
	}
	pci_set_master(mite->pcidev);
	if (pci_request_regions(mite->pcidev, "mite")) {
		pr_err("mite: failed to request mite io regions.\n");
		return -EIO;
	}
	addr = pci_resource_start(mite->pcidev, 0);
	mite->mite_phys_addr = addr;
	mite->mite_io_addr = ioremap(addr, pci_resource_len(mite->pcidev, 0));
	if (!mite->mite_io_addr) {
		pr_err("mite: failed to remap mite io memory address.\n");
		return -ENOMEM;
	}
	pr_info("mite: 0x%08lx mapped to %p\n", mite->mite_phys_addr, mite->mite_io_addr);
	addr = pci_resource_start(mite->pcidev, 1);
	mite->daq_phys_addr = addr;
	mite->daq_io_addr = ioremap(mite->daq_phys_addr, pci_resource_len(mite->pcidev, 1));
	if (!mite->daq_io_addr)	{
		pr_err("mite: failed to remap daq io memory address.\n");
		return -ENOMEM;
	}
	pr_info("mite: daq: 0x%08lx mapped to %p\n", mite->daq_phys_addr, mite->daq_io_addr);
	writel(mite->daq_phys_addr | WENAB, mite->mite_io_addr + MITE_IODWBSR);
	mite->used = 1;
	return 0;
}

void mite_cleanup(void)
{
	struct mite_struct *mite, *next;

	for (mite = mite_devices; mite; mite = next) {
		next = mite->next;
		if (mite->pcidev)
			pci_dev_put(mite->pcidev);
		kfree(mite);
	}
}

void mite_unsetup(struct mite_struct *mite)
{
	if (!mite)
		return;
	if (mite->mite_io_addr)	{
		iounmap(mite->mite_io_addr);
		mite->mite_io_addr = NULL;
	}
	if (mite->daq_io_addr) {
		iounmap(mite->daq_io_addr);
		mite->daq_io_addr = NULL;
	}
	if (mite->mite_phys_addr) {
		pci_release_regions(mite->pcidev);
		pci_disable_device(mite->pcidev);
		mite->mite_phys_addr = 0;
	}
	mite->used = 0;
}

void mite_list_devices(void)
{
	struct mite_struct *mite, *next;

	pr_info("Available NI PCI device IDs:");
	if (mite_devices)
		for (mite = mite_devices; mite; mite = next) {
			next = mite->next;
			pr_info(" 0x%04x", mite_device_id(mite));
			if (mite->used)
				pr_info("(used)");
	}
	pr_info("\n");
}
吵醒沈睡冰山後從容脫逃 你總是有辦法輕易做到