1/* Intel PRO/1000 Family Driver
2 * Copyright (C) 2004 Marcus Overhagen <marcus@overhagen.de>. All rights reserved.
3 *
4 * Permission to use, copy, modify and distribute this software and its
5 * documentation for any purpose and without fee is hereby granted, provided
6 * that the above copyright notice appear in all copies, and that both the
7 * copyright notice and this permission notice appear in supporting documentation.
8 *
9 * Marcus Overhagen makes no representations about the suitability of this software
10 * for any purpose. It is provided "as is" without express or implied warranty.
11 *
12 * MARCUS OVERHAGEN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
13 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL MARCUS
14 * OVERHAGEN BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
15 * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
17 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19#include <KernelExport.h>
20#include <Errors.h>
21#include <stdlib.h>
22#include <stdio.h>
23#include <string.h>
24
25#include "debug.h"
26#include "timer.h"
27#include "device.h"
28#include "driver.h"
29#include "mempool.h"
30
31int32 api_version = B_CUR_DRIVER_API_VERSION;
32
33pci_module_info *gPci;
34
35char* gDevNameList[MAX_CARDS + 1];
36pci_info *gDevList[MAX_CARDS];
37
38static const char *
39identify_device(const pci_info *info)
40{
41	if (info->vendor_id != 0x8086)
42		return 0;
43	switch (info->device_id) {
44		case 0x1000: return "82542";
45		case 0x1001: return "82543GC FIBER";
46		case 0x1004: return "82543GC COPPER";
47		case 0x1008: return "82544EI COPPER";
48		case 0x1009: return "82544EI FIBER";
49		case 0x100C: return "82544GC COPPER";
50		case 0x100D: return "82544GC LOM";
51		case 0x100E: return "82540EM";
52		case 0x100F: return "82545EM COPPER";
53		case 0x1010: return "82546EB COPPER";
54		case 0x1011: return "82545EM FIBER";
55		case 0x1012: return "82546EB FIBER";
56		case 0x1013: return "82541EI";
57		case 0x1014: return "unknown 1014";
58		case 0x1015: return "82540EM LOM";
59		case 0x1016: return "82540EP LOM";
60		case 0x1017: return "82540EP";
61		case 0x1018: return "82541EI MOBILE";
62		case 0x1019: return "82547EI";
63		case 0x101A: return "unknown 101A";
64		case 0x101D: return "82546EB QUAD COPPER";
65		case 0x101E: return "82540EP LP";
66		case 0x1026: return "82545GM COPPER";
67		case 0x1027: return "82545GM FIBER";
68		case 0x1028: return "82545GM SERDES";
69		case 0x1075: return "82547GI";
70		case 0x1076: return "82541GI";
71		case 0x1077: return "82541GI MOBILE";
72		case 0x1078: return "82541ER";
73		case 0x1079: return "82546GB COPPER";
74		case 0x107A: return "82546GB FIBER";
75		case 0x107B: return "82546GB SERDES";
76		case 0x107C: return "82541PI";
77		default: return 0;
78	}
79}
80
81status_t
82init_hardware(void)
83{
84	pci_module_info *pci;
85	pci_info info;
86	status_t res;
87	int i;
88
89	INIT_DEBUGOUT("init_hardware()");
90
91	if (get_module(B_PCI_MODULE_NAME, (module_info **)&pci) < B_OK)
92		return B_ERROR;
93	for (res = B_ERROR, i = 0; pci->get_nth_pci_info(i, &info) == B_OK; i++) {
94		if (identify_device(&info)) {
95			res = B_OK;
96			break;
97		}
98	}
99	put_module(B_PCI_MODULE_NAME);
100
101	return res;
102}
103
104
105status_t
106init_driver(void)
107{
108	struct pci_info *item;
109	int index;
110	int cards;
111
112#ifdef DEBUG
113	set_dprintf_enabled(true);
114	load_driver_symbols("ipro1000");
115#endif
116
117	dprintf("ipro1000: " INFO "\n");
118
119	item = (pci_info *)malloc(sizeof(pci_info));
120	if (!item)
121		return B_NO_MEMORY;
122
123	if (get_module(B_PCI_MODULE_NAME, (module_info **)&gPci) < B_OK) {
124		free(item);
125		return B_ERROR;
126	}
127
128	for (cards = 0, index = 0; gPci->get_nth_pci_info(index++, item) == B_OK; ) {
129		const char *info = identify_device(item);
130		if (info) {
131			char name[64];
132			sprintf(name, "net/ipro1000/%d", cards);
133			dprintf("ipro1000: /dev/%s is a %s\n", name, info);
134			gDevList[cards] = item;
135			gDevNameList[cards] = strdup(name);
136			gDevNameList[cards + 1] = NULL;
137			cards++;
138			item = (pci_info *)malloc(sizeof(pci_info));
139			if (!item)
140				goto err_outofmem;
141			if (cards == MAX_CARDS)
142				break;
143		}
144	}
145
146	free(item);
147
148	if (!cards)
149		goto err_cards;
150
151	if (initialize_timer() != B_OK) {
152		ERROROUT("timer init failed");
153		goto err_timer;
154	}
155
156	if (mempool_init(cards * 768) != B_OK) {
157		ERROROUT("mempool init failed");
158		goto err_mempool;
159	}
160
161	return B_OK;
162
163err_mempool:
164	terminate_timer();
165err_timer:
166err_cards:
167err_outofmem:
168	for (index = 0; index < cards; index++) {
169		free(gDevList[index]);
170		free(gDevNameList[index]);
171	}
172	put_module(B_PCI_MODULE_NAME);
173	return B_ERROR;
174}
175
176
177void
178uninit_driver(void)
179{
180	int32 i;
181
182	INIT_DEBUGOUT("uninit_driver()");
183
184	terminate_timer();
185
186	mempool_exit();
187
188	for (i = 0; gDevNameList[i] != NULL; i++) {
189		free(gDevList[i]);
190		free(gDevNameList[i]);
191	}
192
193	put_module(B_PCI_MODULE_NAME);
194}
195
196
197device_hooks
198gDeviceHooks = {
199	ipro1000_open,
200	ipro1000_close,
201	ipro1000_free,
202	ipro1000_control,
203	ipro1000_read,
204	ipro1000_write,
205};
206
207
208const char**
209publish_devices()
210{
211	return (const char**)gDevNameList;
212}
213
214
215device_hooks*
216find_device(const char* name)
217{
218	return &gDeviceHooks;
219}
220