1193326Sed/*
2193326Sed * Copyright (C) 2007 JiSheng Zhang <jszhang3@gmail.com>. All rights reserved
3353358Sdim * Distributed under the terms of the MIT license.
4353358Sdim *
5353358Sdim * Kernel driver for firewire
6193326Sed */
7193326Sed
8193326Sed#include <OS.h>
9193326Sed#include <KernelExport.h>
10193326Sed#include <SupportDefs.h>
11193326Sed#include <PCI.h>
12193326Sed
13341825Sdim#include <stdlib.h>
14249423Sdim#include <stdio.h>
15360784Sdim#include <string.h>
16193326Sed#include <malloc.h>
17338697Sdim#include <dpc.h>
18193326Sed
19360784Sdim#include "fwdebug.h"
20193326Sed#include "queue.h"
21234353Sdim#include "fwglue.h"
22193326Sed#include "firewire.h"
23249423Sdim#include "iec13213.h"
24249423Sdim#include "firewirereg.h"
25249423Sdim#include "fwdma.h"
26360784Sdim#include "fwohcireg.h"
27249423Sdim#include "fwohcivar.h"
28193326Sed#include "firewire_module.h"
29193326Sed
30193326Sedstatus_t fwohci_pci_attach(int index);
31193326Sedstatus_t fwohci_pci_detach(int index);
32193326Sedpci_info *pciInfo[MAX_CARDS];
33193326Sedfwohci_softc_t *gFwohci_softc[MAX_CARDS];
34193326Sedstruct firewire_softc *gFirewire_softc[MAX_CARDS];
35193326Sedpci_module_info	*gPci;
36199990Srdivackydpc_module_info *gDpc;
37193326Sed
38193326Sedstruct supported_device{
39218893Sdim	uint16 vendor_id;
40288943Sdim	uint32 device_id;
41208600Srdivacky	const char *name;
42218893Sdim};
43218893Sdim
44218893Sdimstruct supported_device supported_devices[] = {
45218893Sdim	{FW_VENDORID_NATSEMI, FW_DEVICE_CS4210, "National Semiconductor CS4210"},
46239462Sdim	{FW_VENDORID_NEC, FW_DEVICE_UPD861, "NEC uPD72861"},
47239462Sdim	{FW_VENDORID_NEC, FW_DEVICE_UPD871, "NEC uPD72871/2"},
48239462Sdim	{FW_VENDORID_NEC, FW_DEVICE_UPD72870, "NEC uPD72870"},
49239462Sdim	{FW_VENDORID_NEC, FW_DEVICE_UPD72873, "NEC uPD72873"},
50218893Sdim	{FW_VENDORID_NEC, FW_DEVICE_UPD72874, "NEC uPD72874"},
51341825Sdim	{FW_VENDORID_SIS, FW_DEVICE_7007, "SiS 7007"},
52341825Sdim	{FW_VENDORID_TI, FW_DEVICE_TITSB22, "Texas Instruments TSB12LV22"},
53341825Sdim	{FW_VENDORID_TI, FW_DEVICE_TITSB23, "Texas Instruments TSB12LV23"},
54341825Sdim	{FW_VENDORID_TI, FW_DEVICE_TITSB26, "Texas Instruments TSB12LV26"},
55341825Sdim	{FW_VENDORID_TI, FW_DEVICE_TITSB43, "Texas Instruments TSB43AA22"},
56341825Sdim	{FW_VENDORID_TI, FW_DEVICE_TITSB43A, "Texas Instruments TSB43AB22/A"},
57341825Sdim	{FW_VENDORID_TI, FW_DEVICE_TITSB43AB21, "Texas Instruments TSB43AB21/A/AI/A-EP"},
58341825Sdim	{FW_VENDORID_TI, FW_DEVICE_TITSB43AB23, "Texas Instruments TSB43AB23"},
59341825Sdim	{FW_VENDORID_TI, FW_DEVICE_TITSB82AA2, "Texas Instruments TSB82AA2"},
60193326Sed	{FW_VENDORID_TI, FW_DEVICE_TIPCI4450, "Texas Instruments PCI4450"},
61288943Sdim	{FW_VENDORID_TI, FW_DEVICE_TIPCI4410A, "Texas Instruments PCI4410A"},
62288943Sdim	{FW_VENDORID_TI, FW_DEVICE_TIPCI4451, "Texas Instruments PCI4451"},
63288943Sdim	{FW_VENDORID_VIA, FW_DEVICE_VT6306, "VIA Fire II (VT6306)"},
64193326Sed	{FW_VENDORID_RICOH, FW_DEVICE_R5C551, "Ricoh R5C551"},
65193326Sed	{FW_VENDORID_RICOH, FW_DEVICE_R5C552, "Ricoh R5C552"},
66193326Sed	{FW_VENDORID_APPLE, FW_DEVICE_PANGEA, "Apple Pangea"},
67193326Sed	{FW_VENDORID_APPLE, FW_DEVICE_UNINORTH, "Apple UniNorth"},
68193326Sed	{FW_VENDORID_LUCENT, FW_DEVICE_FW322, "Lucent FW322/323"},
69193326Sed	{FW_VENDORID_INTEL, FW_DEVICE_82372FB, "Intel 82372FB"},
70193326Sed	{FW_VENDORID_ADAPTEC, FW_DEVICE_AIC5800, "Adaptec AHA-894x/AIC-5800"},
71193326Sed	{FW_VENDORID_SUN, FW_DEVICE_PCIO2FW, "Sun PCIO-2"},
72193326Sed	{FW_VENDORID_SONY, FW_DEVICE_CXD3222, "Sony i.LINK (CXD3222)"},
73193326Sed	{0, 0, NULL}
74341825Sdim};
75341825Sdim
76341825Sdim
77341825Sdimstatic int
78341825Sdimfind_device_name(pci_info *info)
79193326Sed{
80341825Sdim	struct supported_device *device;
81341825Sdim	for (device = supported_devices; device->name; device++) {
82341825Sdim		if (info->vendor_id == device->vendor_id
83296417Sdim			&& info->device_id == device->device_id >> 16) {
84239462Sdim			dprintf("%s\n", device->name);
85239462Sdim			return 1;
86193326Sed		}
87226633Sdim	}
88208600Srdivacky	return 0;
89296417Sdim}
90338697Sdim
91234353Sdim
92226633Sdim#if 0
93234353Sdimstatic status_t
94226633Sdimfw_add_child(const char *childname,
95226633Sdim		const struct firewire_notify_hooks *hooks)
96226633Sdim{
97226633Sdim	status_t status;
98208600Srdivacky	int i;
99208600Srdivacky	TRACE("add child %s\n", childname);
100193326Sed	for (i = 0; gFirewire_softc[i] != NULL; i++) {
101193326Sed		status = firewire_add_child(gFirewire_softc[i], childname, hooks);
102193326Sed		if (status != B_OK)
103198092Srdivacky			return status;
104288943Sdim	}
105288943Sdim
106288943Sdim	return B_OK;
107288943Sdim}
108288943Sdim
109193326Sed
110193326Sedstatic status_t
111193326Sedfw_remove_child(const char *childname)
112193326Sed{
113221345Sdim	status_t status;
114221345Sdim	int i;
115221345Sdim	TRACE("remove child %s\n", childname);
116321369Sdim	for (i = 0; gFirewire_softc[i] != NULL; i++) {
117321369Sdim		status = firewire_remove_child(gFirewire_softc[i], childname);
118321369Sdim		if (status != B_OK)
119321369Sdim			return status;
120321369Sdim	}
121321369Sdim
122321369Sdim	return B_OK;
123193326Sed}
124224145Sdim#endif
125224145Sdim
126224145Sdim
127193326Sedstatic int
128344779Sdimfw_get_handle(int socket, struct firewire_softc **handle)
129344779Sdim{
130344779Sdim	if (handle == NULL)
131344779Sdim		return B_BAD_VALUE;
132193326Sed	if (socket >= 0 && socket < MAX_CARDS && gFirewire_softc[socket]) {
133327952Sdim		*handle = gFirewire_softc[socket];
134193326Sed		return B_OK;
135193326Sed	}
136193326Sed	*handle = NULL;
137224145Sdim	return ENODEV;
138193326Sed}
139193326Sed
140193326Sed
141193326Sedstatic status_t
142198092Srdivackyfw_module_init(void)
143193326Sed{
144198092Srdivacky	status_t status;
145193326Sed	pci_info *info = NULL;
146198092Srdivacky	int i, found;
147193326Sed	fwohci_softc_t *fwohci_sc;
148193326Sed	struct firewire_softc *fw_sc;
149193326Sed
150198398Srdivacky	info = (pci_info*)malloc(sizeof(pci_info));
151193326Sed	if (!info)
152193326Sed		return B_NO_MEMORY;
153341825Sdim
154360784Sdim	if ((status = get_module(B_PCI_MODULE_NAME,(module_info **)&gPci)) != B_OK) {
155360784Sdim		TRACE("pci module unavailable\n");
156360784Sdim		free(info);
157193326Sed		return status;
158193326Sed	}
159193326Sed
160193326Sed	if ((status = get_module(B_DPC_MODULE_NAME,(module_info **)&gDpc)) != B_OK) {
161193326Sed		TRACE("pci module unavailable\n");
162198092Srdivacky		free(info);
163288943Sdim		put_module(B_PCI_MODULE_NAME);
164218893Sdim		return status;
165198092Srdivacky	}
166193326Sed
167314564Sdim	memset(gFwohci_softc, 0, sizeof(gFwohci_softc));
168314564Sdim
169201361Srdivacky	// find devices
170288943Sdim	for (i = 0, found = 0; (status = gPci->get_nth_pci_info(i, info)) == B_OK; i++) {
171193326Sed		if (find_device_name(info)
172353358Sdim				|| ((info->class_base == PCI_serial_bus)
173193326Sed					&& (info->class_sub == PCI_firewire)
174193326Sed					&& (info->class_api == PCI_INTERFACE_OHCI))) {
175251662Sdim			dprintf( "vendor=%x, device=%x, revision = %x\n", info->vendor_id, info->device_id, info->revision);
176353358Sdim			pciInfo[found] = info;
177251662Sdim
178251662Sdim			fwohci_sc = (fwohci_softc_t*)malloc(sizeof(fwohci_softc_t));
179193326Sed			if (!fwohci_sc) {
180193326Sed				free(info);
181309124Sdim				goto err_outofmem;
182234353Sdim			}
183261991Sdim			memset(fwohci_sc, 0, sizeof(fwohci_softc_t));
184218893Sdim			gFwohci_softc[found] = fwohci_sc;
185210299Sed
186199482Srdivacky			fw_sc = (firewire_softc*)malloc(sizeof(struct firewire_softc));
187224145Sdim			if (!fw_sc) {
188218893Sdim				free(info);
189218893Sdim				free(fwohci_sc);
190234353Sdim				goto err_outofmem;
191234353Sdim			}
192234353Sdim			memset(fw_sc, 0, sizeof(struct firewire_softc));
193239462Sdim			gFirewire_softc[found] = fw_sc;
194234353Sdim			gFirewire_softc[found+1] = NULL;
195234353Sdim
196234353Sdim			found++;
197234353Sdim			info = (pci_info*)malloc(sizeof(pci_info));
198234353Sdim			if (!info)
199193326Sed				goto err_outofmem;
200193326Sed
201224145Sdim			if (found == MAX_CARDS)
202224145Sdim				break;
203193326Sed
204200583Srdivacky		}
205226633Sdim	}
206296417Sdim	TRACE("found %d cards\n", found);
207296417Sdim	free(info);
208226633Sdim
209193326Sed	if ((status = initialize_timer()) != B_OK) {
210193326Sed		ERROR("timer init failed\n");
211193326Sed		goto err_timer;
212193326Sed	}
213193326Sed
214193326Sed	for (i = 0; i < found; i++) {
215193326Sed		if (fwohci_pci_attach(i) != B_OK) {
216193326Sed			ERROR("fwohci_pci_attach failed\n");
217193326Sed			goto err_pci;
218193326Sed		}
219193326Sed	}
220193326Sed	return B_OK;
221249423Sdim
222249423Sdimerr_pci:
223288943Sdim	terminate_timer();
224261991Sdimerr_timer:
225249423Sdimerr_outofmem:
226249423Sdim	for (i = 0; i < found; i++) {
227249423Sdim		free(gFirewire_softc[i]);
228239462Sdim		free(gFwohci_softc[i]);
229193326Sed		free(pciInfo[i]);
230193326Sed	}
231341825Sdim	put_module(B_PCI_MODULE_NAME);
232208600Srdivacky	put_module(B_DPC_MODULE_NAME);
233208600Srdivacky	return B_ERROR;
234208600Srdivacky
235208600Srdivacky}
236208600Srdivacky
237208600Srdivackystatic status_t
238208600Srdivackyfw_module_uninit(void)
239208600Srdivacky{
240249423Sdim	int i;
241208600Srdivacky
242208600Srdivacky	terminate_timer();
243208600Srdivacky
244208600Srdivacky	for (i = 0; gFirewire_softc[i] != NULL; i++) {
245208600Srdivacky		fwohci_pci_detach(i);
246208600Srdivacky		free(gFirewire_softc[i]);
247208600Srdivacky		free(gFwohci_softc[i]);
248341825Sdim		free(pciInfo[i]);
249341825Sdim	}
250341825Sdim
251341825Sdim	put_module(B_PCI_MODULE_NAME);
252341825Sdim	put_module(B_DPC_MODULE_NAME);
253341825Sdim
254341825Sdim	return B_OK;
255341825Sdim}
256341825Sdim
257341825Sdim
258341825Sdimstatic status_t
259341825Sdimfw_module_std_ops(int32 op, ...)
260341825Sdim{
261341825Sdim	switch (op) {
262341825Sdim		case B_MODULE_INIT:
263341825Sdim			TRACE("fw_module_init\n");
264341825Sdim			return fw_module_init();
265341825Sdim
266341825Sdim		case B_MODULE_UNINIT:
267341825Sdim			TRACE("fw_module_uninit\n");
268341825Sdim			return fw_module_uninit();
269341825Sdim	}
270341825Sdim	return B_BAD_VALUE;
271341825Sdim}
272341825Sdim
273341825Sdimstatic struct fw_module_info gModuleInfo = {
274341825Sdim	{
275341825Sdim		{
276341825Sdim			FIREWIRE_MODULE_NAME,
277341825Sdim			0,
278341825Sdim			fw_module_std_ops
279341825Sdim		},
280341825Sdim		NULL
281341825Sdim	},
282341825Sdim	fw_noderesolve_nodeid,
283341825Sdim	fw_noderesolve_eui64,
284341825Sdim	fw_asyreq,
285341825Sdim	fw_xferwake,
286341825Sdim	fw_xferwait,
287341825Sdim	fw_bindlookup,
288341825Sdim	fw_bindadd,
289341825Sdim	fw_bindremove,
290341825Sdim	fw_xferlist_add,
291341825Sdim	fw_xferlist_remove,
292341825Sdim	fw_xfer_alloc,
293341825Sdim	fw_xfer_alloc_buf,
294341825Sdim	fw_xfer_done,
295341825Sdim	fw_xfer_unload,
296226633Sdim	fw_xfer_free_buf,
297341825Sdim	fw_xfer_free,
298341825Sdim	fw_asy_callback_free,
299341825Sdim	fw_open_isodma,
300341825Sdim	fw_get_handle,
301341825Sdim	fwdma_malloc_multiseg,
302341825Sdim	fwdma_free_multiseg
303341825Sdim};
304341825Sdim
305341825Sdimmodule_info *modules[] = {
306341825Sdim	(module_info *)&gModuleInfo,
307210299Sed	NULL
308208600Srdivacky};
309208600Srdivacky