xref: /haiku/src/add-ons/kernel/drivers/dvb/cx23882/driver.c (revision ea4f253fd6982ab9fe71251121e8095b784df7fe)
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 "version.h"
33 #include "config.h"
34 #include "driver.h"
35 #include "mktime.h"
36 
37 #define TRACE_DRIVER
38 #ifdef TRACE_DRIVER
39   #define TRACE dprintf
40 #else
41   #define TRACE(a...)
42 #endif
43 
44 typedef struct
45 {
46 	int			vendor;
47 	int			device;
48 	int			subvendor;
49 	int			subdevice;
50 	const char *name;
51 } card_info;
52 
53 int32 				api_version = B_CUR_DRIVER_API_VERSION;
54 pci_module_info *	gPci;
55 static char *		sDevNameList[MAX_CARDS + 1];
56 static pci_info *	sDevList[MAX_CARDS];
57 static int32		sOpenMask;
58 
59 static card_info sCardTable[] =
60 {
61 	{ 0x14f1, 0x8802, 0x0070, 0x9002, "Hauppauge WinTV-NOVA-T model 928" },
62 	{ /* end */ }
63 };
64 
65 
66 typedef struct
67 {
68 	void *	cookie;
69 	int		dev_id;
70 } interface_cookie;
71 
72 
73 static const char *
74 identify_device(const card_info *cards, const pci_info *info)
75 {
76 	for (; cards->name; cards++) {
77 		if (cards->vendor >= 0 && cards->vendor != info->vendor_id)
78 			continue;
79 		if (cards->device >= 0 && cards->device != info->device_id)
80 			continue;
81 		if ((info->header_type & PCI_header_type_mask) != PCI_header_type_generic)
82 			continue;
83 		if (cards->subvendor >= 0 && cards->subvendor != info->u.h0.subsystem_vendor_id)
84 			continue;
85 		if (cards->subdevice >= 0 && cards->subdevice != info->u.h0.subsystem_id)
86 			continue;
87 		return cards->name;
88 	}
89 	return NULL;
90 }
91 
92 
93 status_t
94 init_hardware(void)
95 {
96 	pci_info info;
97 	status_t res;
98 	int i;
99 
100 	TRACE("cx23882: init_hardware()\n");
101 
102 	if (get_module(B_PCI_MODULE_NAME, (module_info **)&gPci) < B_OK)
103 		return B_ERROR;
104 	for (res = B_ERROR, i = 0; gPci->get_nth_pci_info(i, &info) == B_OK; i++) {
105 		if (identify_device(sCardTable, &info)) {
106 			res = B_OK;
107 			break;
108 		}
109 	}
110 	put_module(B_PCI_MODULE_NAME);
111 	gPci = NULL;
112 
113 	return res;
114 }
115 
116 
117 status_t
118 init_driver(void)
119 {
120 	struct pci_info *item;
121 	int index;
122 	int cards;
123 
124 #ifdef DEBUG
125 	set_dprintf_enabled(true);
126 	load_driver_symbols("cx23882");
127 #endif
128 
129 	dprintf(gBanner);
130 
131 	item = (pci_info *)malloc(sizeof(pci_info));
132 	if (!item)
133 		return B_NO_MEMORY;
134 
135 	if (get_module(B_PCI_MODULE_NAME, (module_info **)&gPci) < B_OK) {
136 		free(item);
137 		return B_ERROR;
138 	}
139 
140 	for (cards = 0, index = 0; gPci->get_nth_pci_info(index++, item) == B_OK; ) {
141 		const char *info = identify_device(sCardTable, item);
142 		if (info) {
143 			char name[64];
144 			sprintf(name, "dvb/cx23882/%d", cards + 1);
145 			dprintf("cx23882: /dev/%s is a %s\n", name, info);
146 			sDevList[cards] = item;
147 			sDevNameList[cards] = strdup(name);
148 			sDevNameList[cards + 1] = NULL;
149 			cards++;
150 			item = (pci_info *)malloc(sizeof(pci_info));
151 			if (!item)
152 				goto err_outofmem;
153 			if (cards == MAX_CARDS)
154 				break;
155 		}
156 	}
157 
158 	free(item);
159 
160 	if (!cards)
161 		goto err_cards;
162 
163 	return B_OK;
164 
165 err_outofmem:
166 	TRACE("cx23882: err_outofmem\n");
167 	for (index = 0; index < cards; index++) {
168 		free(sDevList[index]);
169 		free(sDevNameList[index]);
170 	}
171 err_cards:
172 	put_module(B_PCI_MODULE_NAME);
173 	return B_ERROR;
174 }
175 
176 
177 void
178 uninit_driver(void)
179 {
180 	int32 i;
181 
182 	TRACE("cx23882: uninit_driver\n");
183 
184 	for (i = 0; sDevNameList[i] != NULL; i++) {
185 		free(sDevList[i]);
186 		free(sDevNameList[i]);
187 	}
188 
189 	put_module(B_PCI_MODULE_NAME);
190 }
191 
192 
193 static status_t
194 driver_open(const char *name, uint32 flags, void** _cookie)
195 {
196 	interface_cookie *cookie;
197 	char *deviceName;
198 	status_t status;
199 	int dev_id;
200 	int mask;
201 
202 	TRACE("cx23882: driver open\n");
203 
204 	for (dev_id = 0; (deviceName = sDevNameList[dev_id]) != NULL; dev_id++) {
205 		if (!strcmp(name, deviceName))
206 			break;
207 	}
208 	if (deviceName == NULL) {
209 		TRACE("cx23882: invalid device name\n");
210 		return B_ERROR;
211 	}
212 
213 	// allow only one concurrent access
214 	mask = 1 << dev_id;
215 	if (atomic_or(&sOpenMask, mask) & mask)
216 		return B_BUSY;
217 
218 	cookie = (interface_cookie *)malloc(sizeof(interface_cookie));
219 	if (!cookie)
220 		return B_NO_MEMORY;
221 
222 	cookie->dev_id = dev_id;
223 	status = interface_attach(&cookie->cookie, sDevList[dev_id]);
224 	if (status != B_OK) {
225 		free(cookie);
226 		atomic_and(&sOpenMask, ~(1 << dev_id));
227 		return status;
228 	}
229 
230 	*_cookie = cookie;
231 	return B_OK;
232 }
233 
234 
235 static status_t
236 driver_close(void* cookie)
237 {
238 	TRACE("cx23882: driver close\n");
239 	interface_detach(((interface_cookie *)cookie)->cookie);
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 	return B_OK;
250 }
251 
252 
253 static status_t
254 driver_read(void* cookie, off_t position, void *buf, size_t* num_bytes)
255 {
256 	TRACE("cx23882: driver read\n");
257 	*num_bytes = 0; // required by design for read hook!
258 	return B_ERROR;
259 }
260 
261 
262 static status_t
263 driver_write(void* cookie, off_t position, const void* buffer, size_t* num_bytes)
264 {
265 	TRACE("cx23882: driver write\n");
266 	*num_bytes = 0; // not sure if required for write hook
267 	return B_ERROR;
268 }
269 
270 
271 static status_t
272 driver_control(void *cookie, uint32 op, void *arg, size_t len)
273 {
274 //	TRACE("cx23882: driver control\n");
275 	return interface_ioctl(((interface_cookie *)cookie)->cookie, op, arg, len);
276 }
277 
278 
279 static device_hooks
280 sDeviceHooks = {
281 	driver_open,
282 	driver_close,
283 	driver_free,
284 	driver_control,
285 	driver_read,
286 	driver_write,
287 };
288 
289 
290 const char**
291 publish_devices(void)
292 {
293 	return (const char**)sDevNameList;
294 }
295 
296 
297 device_hooks*
298 find_device(const char* name)
299 {
300 	return &sDeviceHooks;
301 }
302