1/*
2	Driver for Intel(R) PRO/Wireless 2100 devices.
3	Copyright (C) 2006 Michael Lotz <mmlr@mlotz.ch>
4	Released under the terms of the MIT license.
5*/
6
7#include <Drivers.h>
8#include <KernelExport.h>
9#include <PCI.h>
10#include <stdio.h>
11#include <string.h>
12
13#include "driver.h"
14#include "ipw2100.h"
15#include "kernel_cpp.h"
16
17
18status_t	ipw2100_open(const char *name, uint32 flags, void **cookie);
19status_t	ipw2100_close(void *cookie);
20status_t	ipw2100_free(void *cookie);
21status_t	ipw2100_control(void *cookie, uint32 op, void *args, size_t length);
22status_t	ipw2100_read(void *cookie, off_t position, void *buffer, size_t *numBytes);
23status_t	ipw2100_write(void *cookie, off_t position, const void *buffer, size_t *numBytes);
24
25
26int32 api_version = B_CUR_DRIVER_API_VERSION;
27
28
29pci_module_info *gPCIModule;
30char *gDeviceNameList[MAX_INSTANCES + 1];
31pci_info *gDeviceList[MAX_INSTANCES];
32int32 gOpenMask = 0;
33
34device_hooks gDeviceHooks = {
35	ipw2100_open,
36	ipw2100_close,
37	ipw2100_free,
38	ipw2100_control,
39	ipw2100_read,
40	ipw2100_write
41};
42
43
44const char *
45identify_device(const pci_info *info)
46{
47	if (info->vendor_id != VENDOR_ID_INTEL)
48		return NULL;
49
50	switch (info->device_id) {
51		case 0x1043: return "Intel(R) PRO/Wireless 2100";
52	}
53
54	return NULL;
55}
56
57
58status_t
59init_hardware()
60{
61#ifdef TRACE_IPW2100
62	set_dprintf_enabled(true);
63#endif
64
65	//TRACE((DRIVER_NAME": init hardware\n"));
66
67	pci_module_info *module;
68	status_t result = get_module(B_PCI_MODULE_NAME, (module_info **)&module);
69	if (result < B_OK)
70		return result;
71
72	int32 index = 0;
73	result = B_ERROR;
74	pci_info info;
75	while (module->get_nth_pci_info(index++, &info) == B_OK) {
76		const char *deviceName = identify_device(&info);
77		if (deviceName) {
78			TRACE((DRIVER_NAME": found device \"%s\"\n", deviceName));
79			result = B_OK;
80			break;
81		}
82	}
83
84	put_module(B_PCI_MODULE_NAME);
85	return result;
86}
87
88
89status_t
90init_driver()
91{
92	TRACE((DRIVER_NAME": init driver\n"));
93
94	for (int32 i = 0; i < MAX_INSTANCES; i++)
95		gDeviceList[i] = NULL;
96	for (int32 i = 0; i < MAX_INSTANCES + 1; i++)
97		gDeviceNameList[i] = NULL;
98
99	pci_info *info = new pci_info;
100	if (!info)
101		return B_NO_MEMORY;
102
103	status_t result = get_module(B_PCI_MODULE_NAME, (module_info **)&gPCIModule);
104	if (result < B_OK) {
105		delete info;
106		return result;
107	}
108
109	int32 index = 0;
110	int32 count = 0;
111	while (gPCIModule->get_nth_pci_info(index++, info) == B_OK
112		&& count < MAX_INSTANCES) {
113		const char *deviceName = identify_device(info);
114		if (!deviceName)
115			continue;
116
117		char publishName[64];
118		sprintf(publishName, "net/ipw2100/%ld", count);
119
120		gDeviceList[count] = info;
121		gDeviceNameList[count] = strdup(publishName);
122
123		info = new pci_info;
124		if (!info)
125			goto error_out_of_memory;
126
127		dprintf(DRIVER_NAME": will publish an \"%s\" as device %ld to /dev/%s\n", deviceName, count, publishName);
128		count++;
129	}
130
131	delete info;
132	return B_OK;
133
134error_out_of_memory:
135	for (int32 i = 0; i < MAX_INSTANCES; i++) {
136		free(gDeviceNameList[i]);
137		delete gDeviceList[i];
138		gDeviceNameList[i] = NULL;
139		gDeviceList[i] = NULL;
140	}
141
142	put_module(B_PCI_MODULE_NAME);
143	return B_ERROR;
144}
145
146
147void
148uninit_driver()
149{
150	TRACE((DRIVER_NAME": uninit driver\n"));
151	for (int32 i = 0; i < MAX_INSTANCES; i++) {
152		free(gDeviceNameList[i]);
153		delete gDeviceList[i];
154		gDeviceNameList[i] = NULL;
155		gDeviceList[i] = NULL;
156	}
157
158	put_module(B_PCI_MODULE_NAME);
159}
160
161
162const char **
163publish_devices(void)
164{
165	//TRACE((DRIVER_NAME": publish devices\n"));
166	return (const char **)gDeviceNameList;
167}
168
169
170device_hooks *
171find_device(const char *name)
172{
173	//TRACE((DRIVER_NAME": find device \"%s\"\n", name));
174
175	for (int32 i = 0; i < MAX_INSTANCES; i++) {
176		if (strcmp(gDeviceNameList[i], name) == 0)
177			return &gDeviceHooks;
178	}
179
180	TRACE_ALWAYS((DRIVER_NAME": couldn't find device \"%s\"\n", name));
181	return NULL;
182}
183
184
185//#pragma mark -
186
187
188status_t
189ipw2100_open(const char *name, uint32 flags, void **cookie)
190{
191	//TRACE((DRIVER_NAME": open device\n"));
192	int32 deviceID = -1;
193	for (int32 i = 0; i < MAX_INSTANCES && gDeviceNameList[i]; i++) {
194		if (strcmp(gDeviceNameList[i], name) == 0) {
195			deviceID = i;
196			break;
197		}
198	}
199
200	if (deviceID < 0)
201		return B_ERROR;
202
203	// allow only one concurrent access
204	int32 mask = 1 << deviceID;
205	if (atomic_or(&gOpenMask, mask) & mask)
206		return B_BUSY;
207
208	IPW2100 *device = new IPW2100(deviceID, gDeviceList[deviceID], gPCIModule);
209	status_t result = device->InitCheck();
210	if (device->InitCheck() < B_OK) {
211		delete device;
212		return result;
213	}
214
215	*cookie = (void *)device;
216	return device->Open(flags);
217}
218
219
220status_t
221ipw2100_close(void *cookie)
222{
223	//TRACE((DRIVER_NAME": close device\n"));
224	IPW2100 *device = (IPW2100 *)cookie;
225	return device->Close();
226}
227
228
229status_t
230ipw2100_free(void *cookie)
231{
232	//TRACE((DRIVER_NAME": free device\n"));
233	IPW2100 *device = (IPW2100 *)cookie;
234
235	int32 mask = 1 << device->DeviceID();
236
237	device->Free();
238	delete device;
239
240	atomic_and(&gOpenMask, ~mask);
241	return B_OK;
242}
243
244
245status_t
246ipw2100_control(void *cookie, uint32 op, void *args, size_t length)
247{
248	//TRACE((DRIVER_NAME": control device\n"));
249	IPW2100 *device = (IPW2100 *)cookie;
250	return device->Control(op, args, length);
251}
252
253
254status_t
255ipw2100_read(void *cookie, off_t position, void *buffer, size_t *numBytes)
256{
257	//TRACE((DRIVER_NAME": read device\n"));
258	IPW2100 *device = (IPW2100 *)cookie;
259	return device->Read(position, buffer, numBytes);
260}
261
262
263status_t
264ipw2100_write(void *cookie, off_t position, const void *buffer, size_t *numBytes)
265{
266	//TRACE((DRIVER_NAME": write device\n"));
267	IPW2100 *device = (IPW2100 *)cookie;
268	return device->Write(position, buffer, numBytes);
269}
270