xref: /haiku/src/add-ons/kernel/drivers/dvb/cx23882/driver.c (revision 16d5c24e533eb14b7b8a99ee9f3ec9ba66335b1e)
1 /*
2  * Copyright (c) 2004-2007 Marcus Overhagen <marcus@overhagen.de>
3  *
4  * Permission is hereby granted, free of charge, to any person
5  * obtaining a copy of this software and associated documentation
6  * files (the "Software"), to deal in the Software without restriction,
7  * including without limitation the rights to use, copy, modify,
8  * merge, publish, distribute, sublicense, and/or sell copies of
9  * the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22  * OTHER DEALINGS IN THE SOFTWARE.
23  */
24 
25 #include <KernelExport.h>
26 #include <Drivers.h>
27 #include <Errors.h>
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <string.h>
31 
32 #include "config.h"
33 #include "driver.h"
34 #include "dvb_interface.h"
35 
36 #define TRACE_DRIVER
37 #ifdef TRACE_DRIVER
38   #define TRACE dprintf
39 #else
40   #define TRACE(a...)
41 #endif
42 
43 typedef struct
44 {
45 	int			vendor;
46 	int			device;
47 	int			subvendor;
48 	int			subdevice;
49 	const char *name;
50 } card_info;
51 
52 int32 				api_version = B_CUR_DRIVER_API_VERSION;
53 pci_module_info *	gPci;
54 static char *		sDevNameList[MAX_CARDS + 1];
55 static pci_info *	sDevList[MAX_CARDS];
56 static int32		sOpenMask;
57 
58 static card_info sCardTable[] =
59 {
60 	{ 0x14f1, 0x8802, 0x0070, 0x9002, "Hauppauge WinTV-NOVA-T model 928" },
61 	{ /* end */ }
62 };
63 
64 
65 typedef struct
66 {
67 	void *	cookie;
68 	int		dev_id;
69 } interface_cookie;
70 
71 
72 static const char *
73 identify_device(const card_info *cards, const pci_info *info)
74 {
75 	for (; cards->name; cards++) {
76 		if (cards->vendor >= 0 && cards->vendor != info->vendor_id)
77 			continue;
78 		if (cards->device >= 0 && cards->device != info->device_id)
79 			continue;
80 		if ((info->header_type & PCI_header_type_mask) != PCI_header_type_generic)
81 			continue;
82 		if (cards->subvendor >= 0 && cards->subvendor != info->u.h0.subsystem_vendor_id)
83 			continue;
84 		if (cards->subdevice >= 0 && cards->subdevice != info->u.h0.subsystem_id)
85 			continue;
86 		return cards->name;
87 	}
88 	return NULL;
89 }
90 
91 
92 status_t
93 init_hardware(void)
94 {
95 	pci_info info;
96 	status_t res;
97 	int i;
98 
99 	TRACE("cx23882: init_hardware()\n");
100 
101 	if (get_module(B_PCI_MODULE_NAME, (module_info **)&gPci) < B_OK)
102 		return B_ERROR;
103 	for (res = B_ERROR, i = 0; gPci->get_nth_pci_info(i, &info) == B_OK; i++) {
104 		if (identify_device(sCardTable, &info)) {
105 			res = B_OK;
106 			break;
107 		}
108 	}
109 	put_module(B_PCI_MODULE_NAME);
110 	gPci = NULL;
111 
112 	return res;
113 }
114 
115 
116 status_t
117 init_driver(void)
118 {
119 	struct pci_info *item;
120 	int index;
121 	int cards;
122 
123 #if defined(DEBUG) && !defined(__HAIKU__)
124 	set_dprintf_enabled(true);
125 	load_driver_symbols("cx23882");
126 #endif
127 
128 	dprintf(INFO);
129 
130 	item = (pci_info *)malloc(sizeof(pci_info));
131 	if (!item)
132 		return B_NO_MEMORY;
133 
134 	if (get_module(B_PCI_MODULE_NAME, (module_info **)&gPci) < B_OK) {
135 		free(item);
136 		return B_ERROR;
137 	}
138 
139 	for (cards = 0, index = 0; gPci->get_nth_pci_info(index++, item) == B_OK; ) {
140 		const char *info = identify_device(sCardTable, item);
141 		if (info) {
142 			char name[64];
143 			sprintf(name, "dvb/cx23882/%d", cards + 1);
144 			dprintf("cx23882: /dev/%s is a %s\n", name, info);
145 			sDevList[cards] = item;
146 			sDevNameList[cards] = strdup(name);
147 			sDevNameList[cards + 1] = NULL;
148 			cards++;
149 			item = (pci_info *)malloc(sizeof(pci_info));
150 			if (!item)
151 				goto err_outofmem;
152 			if (cards == MAX_CARDS)
153 				break;
154 		}
155 	}
156 
157 	free(item);
158 
159 	if (!cards)
160 		goto err_cards;
161 
162 	return B_OK;
163 
164 err_outofmem:
165 	TRACE("cx23882: err_outofmem\n");
166 	for (index = 0; index < cards; index++) {
167 		free(sDevList[index]);
168 		free(sDevNameList[index]);
169 	}
170 err_cards:
171 	put_module(B_PCI_MODULE_NAME);
172 	return B_ERROR;
173 }
174 
175 
176 void
177 uninit_driver(void)
178 {
179 	int32 i;
180 
181 	TRACE("cx23882: uninit_driver\n");
182 
183 	for (i = 0; sDevNameList[i] != NULL; i++) {
184 		free(sDevList[i]);
185 		free(sDevNameList[i]);
186 	}
187 
188 	put_module(B_PCI_MODULE_NAME);
189 }
190 
191 
192 static status_t
193 driver_open(const char *name, uint32 flags, void** _cookie)
194 {
195 	interface_cookie *cookie;
196 	char *deviceName;
197 	status_t status;
198 	int dev_id;
199 	int mask;
200 
201 	TRACE("cx23882: driver open\n");
202 
203 	for (dev_id = 0; (deviceName = sDevNameList[dev_id]) != NULL; dev_id++) {
204 		if (!strcmp(name, deviceName))
205 			break;
206 	}
207 	if (deviceName == NULL) {
208 		TRACE("cx23882: invalid device name\n");
209 		return B_ERROR;
210 	}
211 
212 	// allow only one concurrent access
213 	mask = 1 << dev_id;
214 	if (atomic_or(&sOpenMask, mask) & mask)
215 		return B_BUSY;
216 
217 	cookie = (interface_cookie *)malloc(sizeof(interface_cookie));
218 	if (!cookie)
219 		return B_NO_MEMORY;
220 
221 	cookie->dev_id = dev_id;
222 	status = interface_attach(&cookie->cookie, sDevList[dev_id]);
223 	if (status != B_OK) {
224 		free(cookie);
225 		atomic_and(&sOpenMask, ~(1 << dev_id));
226 		return status;
227 	}
228 
229 	*_cookie = cookie;
230 	return B_OK;
231 }
232 
233 
234 static status_t
235 driver_close(void* cookie)
236 {
237 	TRACE("cx23882: driver close enter\n");
238 	interface_detach(((interface_cookie *)cookie)->cookie);
239 	TRACE("cx23882: driver close leave\n");
240 	return B_OK;
241 }
242 
243 
244 static status_t
245 driver_free(void* cookie)
246 {
247 	TRACE("cx23882: driver free\n");
248 	atomic_and(&sOpenMask, ~(1 << ((interface_cookie *)cookie)->dev_id));
249 	free(cookie);
250 	return B_OK;
251 }
252 
253 
254 static status_t
255 driver_read(void* cookie, off_t position, void *buf, size_t* num_bytes)
256 {
257 	TRACE("cx23882: driver read\n");
258 	*num_bytes = 0; // required by design for read hook!
259 	return B_ERROR;
260 }
261 
262 
263 static status_t
264 driver_write(void* cookie, off_t position, const void* buffer, size_t* num_bytes)
265 {
266 	TRACE("cx23882: driver write\n");
267 	*num_bytes = 0; // not sure if required for write hook
268 	return B_ERROR;
269 }
270 
271 
272 static status_t
273 driver_control(void *cookie, uint32 op, void *arg, size_t len)
274 {
275 //	TRACE("cx23882: driver control\n");
276 	return interface_ioctl(((interface_cookie *)cookie)->cookie, op, arg, len);
277 }
278 
279 
280 static device_hooks
281 sDeviceHooks = {
282 	driver_open,
283 	driver_close,
284 	driver_free,
285 	driver_control,
286 	driver_read,
287 	driver_write,
288 };
289 
290 
291 const char**
292 publish_devices(void)
293 {
294 	return (const char**)sDevNameList;
295 }
296 
297 
298 device_hooks*
299 find_device(const char* name)
300 {
301 	return &sDeviceHooks;
302 }
303