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 *
identify_device(const card_info * cards,const pci_info * info)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
init_hardware(void)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
init_driver(void)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
uninit_driver(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
driver_open(const char * name,uint32 flags,void ** _cookie)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
driver_close(void * cookie)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
driver_free(void * cookie)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
driver_read(void * cookie,off_t position,void * buf,size_t * num_bytes)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
driver_write(void * cookie,off_t position,const void * buffer,size_t * num_bytes)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
driver_control(void * cookie,uint32 op,void * arg,size_t len)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**
publish_devices(void)292 publish_devices(void)
293 {
294 return (const char**)sDevNameList;
295 }
296
297
298 device_hooks*
find_device(const char * name)299 find_device(const char* name)
300 {
301 return &sDeviceHooks;
302 }
303