xref: /haiku/src/add-ons/kernel/bus_managers/firewire/firewire_module.cpp (revision 7dec2bff46d173ba2e282ddb2b1b70ee50eb7584)
1 /*
2  * Copyright (C) 2007 JiSheng Zhang <jszhang3@gmail.com>. All rights reserved
3  * Distributed under the terms of the MIT license.
4  *
5  * Kernel driver for firewire
6  */
7 
8 #include <OS.h>
9 #include <KernelExport.h>
10 #include <SupportDefs.h>
11 #include <PCI.h>
12 
13 #include <stdlib.h>
14 #include <stdio.h>
15 #include <string.h>
16 #include <malloc.h>
17 #include <dpc.h>
18 
19 #include "fwdebug.h"
20 #include "queue.h"
21 #include "fwglue.h"
22 #include "firewire.h"
23 #include "iec13213.h"
24 #include "firewirereg.h"
25 #include "fwdma.h"
26 #include "fwohcireg.h"
27 #include "fwohcivar.h"
28 #include "firewire_module.h"
29 
30 status_t fwohci_pci_attach(int index);
31 status_t fwohci_pci_detach(int index);
32 pci_info *pciInfo[MAX_CARDS];
33 fwohci_softc_t *gFwohci_softc[MAX_CARDS];
34 struct firewire_softc *gFirewire_softc[MAX_CARDS];
35 pci_module_info	*gPci;
36 dpc_module_info *gDpc;
37 
38 struct supported_device{
39 	uint16 vendor_id;
40 	uint32 device_id;
41 	const char *name;
42 };
43 
44 struct supported_device supported_devices[] = {
45 	{FW_VENDORID_NATSEMI, FW_DEVICE_CS4210, "National Semiconductor CS4210"},
46 	{FW_VENDORID_NEC, FW_DEVICE_UPD861, "NEC uPD72861"},
47 	{FW_VENDORID_NEC, FW_DEVICE_UPD871, "NEC uPD72871/2"},
48 	{FW_VENDORID_NEC, FW_DEVICE_UPD72870, "NEC uPD72870"},
49 	{FW_VENDORID_NEC, FW_DEVICE_UPD72873, "NEC uPD72873"},
50 	{FW_VENDORID_NEC, FW_DEVICE_UPD72874, "NEC uPD72874"},
51 	{FW_VENDORID_SIS, FW_DEVICE_7007, "SiS 7007"},
52 	{FW_VENDORID_TI, FW_DEVICE_TITSB22, "Texas Instruments TSB12LV22"},
53 	{FW_VENDORID_TI, FW_DEVICE_TITSB23, "Texas Instruments TSB12LV23"},
54 	{FW_VENDORID_TI, FW_DEVICE_TITSB26, "Texas Instruments TSB12LV26"},
55 	{FW_VENDORID_TI, FW_DEVICE_TITSB43, "Texas Instruments TSB43AA22"},
56 	{FW_VENDORID_TI, FW_DEVICE_TITSB43A, "Texas Instruments TSB43AB22/A"},
57 	{FW_VENDORID_TI, FW_DEVICE_TITSB43AB21, "Texas Instruments TSB43AB21/A/AI/A-EP"},
58 	{FW_VENDORID_TI, FW_DEVICE_TITSB43AB23, "Texas Instruments TSB43AB23"},
59 	{FW_VENDORID_TI, FW_DEVICE_TITSB82AA2, "Texas Instruments TSB82AA2"},
60 	{FW_VENDORID_TI, FW_DEVICE_TIPCI4450, "Texas Instruments PCI4450"},
61 	{FW_VENDORID_TI, FW_DEVICE_TIPCI4410A, "Texas Instruments PCI4410A"},
62 	{FW_VENDORID_TI, FW_DEVICE_TIPCI4451, "Texas Instruments PCI4451"},
63 	{FW_VENDORID_VIA, FW_DEVICE_VT6306, "VIA Fire II (VT6306)"},
64 	{FW_VENDORID_RICOH, FW_DEVICE_R5C551, "Ricoh R5C551"},
65 	{FW_VENDORID_RICOH, FW_DEVICE_R5C552, "Ricoh R5C552"},
66 	{FW_VENDORID_APPLE, FW_DEVICE_PANGEA, "Apple Pangea"},
67 	{FW_VENDORID_APPLE, FW_DEVICE_UNINORTH, "Apple UniNorth"},
68 	{FW_VENDORID_LUCENT, FW_DEVICE_FW322, "Lucent FW322/323"},
69 	{FW_VENDORID_INTEL, FW_DEVICE_82372FB, "Intel 82372FB"},
70 	{FW_VENDORID_ADAPTEC, FW_DEVICE_AIC5800, "Adaptec AHA-894x/AIC-5800"},
71 	{FW_VENDORID_SUN, FW_DEVICE_PCIO2FW, "Sun PCIO-2"},
72 	{FW_VENDORID_SONY, FW_DEVICE_CXD3222, "Sony i.LINK (CXD3222)"},
73 	{0, 0, NULL}
74 };
75 
76 
77 static int
find_device_name(pci_info * info)78 find_device_name(pci_info *info)
79 {
80 	struct supported_device *device;
81 	for (device = supported_devices; device->name; device++) {
82 		if (info->vendor_id == device->vendor_id
83 			&& info->device_id == device->device_id >> 16) {
84 			dprintf("%s\n", device->name);
85 			return 1;
86 		}
87 	}
88 	return 0;
89 }
90 
91 
92 #if 0
93 static status_t
94 fw_add_child(const char *childname,
95 		const struct firewire_notify_hooks *hooks)
96 {
97 	status_t status;
98 	int i;
99 	TRACE("add child %s\n", childname);
100 	for (i = 0; gFirewire_softc[i] != NULL; i++) {
101 		status = firewire_add_child(gFirewire_softc[i], childname, hooks);
102 		if (status != B_OK)
103 			return status;
104 	}
105 
106 	return B_OK;
107 }
108 
109 
110 static status_t
111 fw_remove_child(const char *childname)
112 {
113 	status_t status;
114 	int i;
115 	TRACE("remove child %s\n", childname);
116 	for (i = 0; gFirewire_softc[i] != NULL; i++) {
117 		status = firewire_remove_child(gFirewire_softc[i], childname);
118 		if (status != B_OK)
119 			return status;
120 	}
121 
122 	return B_OK;
123 }
124 #endif
125 
126 
127 static int
fw_get_handle(int socket,struct firewire_softc ** handle)128 fw_get_handle(int socket, struct firewire_softc **handle)
129 {
130 	if (handle == NULL)
131 		return B_BAD_VALUE;
132 	if (socket >= 0 && socket < MAX_CARDS && gFirewire_softc[socket]) {
133 		*handle = gFirewire_softc[socket];
134 		return B_OK;
135 	}
136 	*handle = NULL;
137 	return ENODEV;
138 }
139 
140 
141 static status_t
fw_module_init(void)142 fw_module_init(void)
143 {
144 	status_t status;
145 	int i, found;
146 	fwohci_softc_t *fwohci_sc;
147 	struct firewire_softc *fw_sc;
148 
149 	pci_info *info = (pci_info*)malloc(sizeof(pci_info));
150 	if (!info)
151 		return B_NO_MEMORY;
152 
153 	if ((status = get_module(B_PCI_MODULE_NAME,(module_info **)&gPci)) != B_OK) {
154 		TRACE("pci module unavailable\n");
155 		free(info);
156 		return status;
157 	}
158 
159 	if ((status = get_module(B_DPC_MODULE_NAME,(module_info **)&gDpc)) != B_OK) {
160 		TRACE("pci module unavailable\n");
161 		free(info);
162 		put_module(B_PCI_MODULE_NAME);
163 		return status;
164 	}
165 
166 	memset(gFwohci_softc, 0, sizeof(gFwohci_softc));
167 
168 	// find devices
169 	for (i = 0, found = 0; (status = gPci->get_nth_pci_info(i, info)) == B_OK; i++) {
170 		if (find_device_name(info)
171 				|| ((info->class_base == PCI_serial_bus)
172 					&& (info->class_sub == PCI_firewire)
173 					&& (info->class_api == PCI_INTERFACE_OHCI))) {
174 			dprintf( "vendor=%x, device=%x, revision = %x\n", info->vendor_id, info->device_id, info->revision);
175 			pciInfo[found] = info;
176 
177 			fwohci_sc = (fwohci_softc_t*)malloc(sizeof(fwohci_softc_t));
178 			if (!fwohci_sc) {
179 				free(info);
180 				goto err_outofmem;
181 			}
182 			memset(fwohci_sc, 0, sizeof(fwohci_softc_t));
183 			gFwohci_softc[found] = fwohci_sc;
184 
185 			fw_sc = (firewire_softc*)malloc(sizeof(struct firewire_softc));
186 			if (!fw_sc) {
187 				free(info);
188 				free(fwohci_sc);
189 				goto err_outofmem;
190 			}
191 			memset(fw_sc, 0, sizeof(struct firewire_softc));
192 			gFirewire_softc[found] = fw_sc;
193 			if (found < MAX_CARDS - 1)
194 				gFirewire_softc[found + 1] = NULL;
195 
196 			found++;
197 			info = (pci_info*)malloc(sizeof(pci_info));
198 			if (!info)
199 				goto err_outofmem;
200 
201 			if (found == MAX_CARDS)
202 				break;
203 
204 		}
205 	}
206 	TRACE("found %d cards\n", found);
207 	free(info);
208 
209 	if ((status = initialize_timer()) != B_OK) {
210 		ERROR("timer init failed\n");
211 		goto err_timer;
212 	}
213 
214 	for (i = 0; i < found; i++) {
215 		if (fwohci_pci_attach(i) != B_OK) {
216 			ERROR("fwohci_pci_attach failed\n");
217 			goto err_pci;
218 		}
219 	}
220 	return B_OK;
221 
222 err_pci:
223 	terminate_timer();
224 err_timer:
225 err_outofmem:
226 	for (i = 0; i < found; i++) {
227 		free(gFirewire_softc[i]);
228 		free(gFwohci_softc[i]);
229 		free(pciInfo[i]);
230 	}
231 	put_module(B_PCI_MODULE_NAME);
232 	put_module(B_DPC_MODULE_NAME);
233 	return B_ERROR;
234 
235 }
236 
237 static status_t
fw_module_uninit(void)238 fw_module_uninit(void)
239 {
240 	int i;
241 
242 	terminate_timer();
243 
244 	for (i = 0; i < MAX_CARDS && gFirewire_softc[i] != NULL; i++) {
245 		fwohci_pci_detach(i);
246 		free(gFirewire_softc[i]);
247 		free(gFwohci_softc[i]);
248 		free(pciInfo[i]);
249 	}
250 
251 	put_module(B_PCI_MODULE_NAME);
252 	put_module(B_DPC_MODULE_NAME);
253 
254 	return B_OK;
255 }
256 
257 
258 static status_t
fw_module_std_ops(int32 op,...)259 fw_module_std_ops(int32 op, ...)
260 {
261 	switch (op) {
262 		case B_MODULE_INIT:
263 			TRACE("fw_module_init\n");
264 			return fw_module_init();
265 
266 		case B_MODULE_UNINIT:
267 			TRACE("fw_module_uninit\n");
268 			return fw_module_uninit();
269 	}
270 	return B_BAD_VALUE;
271 }
272 
273 static struct fw_module_info gModuleInfo = {
274 	{
275 		{
276 			FIREWIRE_MODULE_NAME,
277 			0,
278 			fw_module_std_ops
279 		},
280 		NULL
281 	},
282 	fw_noderesolve_nodeid,
283 	fw_noderesolve_eui64,
284 	fw_asyreq,
285 	fw_xferwake,
286 	fw_xferwait,
287 	fw_bindlookup,
288 	fw_bindadd,
289 	fw_bindremove,
290 	fw_xferlist_add,
291 	fw_xferlist_remove,
292 	fw_xfer_alloc,
293 	fw_xfer_alloc_buf,
294 	fw_xfer_done,
295 	fw_xfer_unload,
296 	fw_xfer_free_buf,
297 	fw_xfer_free,
298 	fw_asy_callback_free,
299 	fw_open_isodma,
300 	fw_get_handle,
301 	fwdma_malloc_multiseg,
302 	fwdma_free_multiseg
303 };
304 
305 module_info *modules[] = {
306 	(module_info *)&gModuleInfo,
307 	NULL
308 };
309