vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / kernel / drivers / dvb / cx23882 / dvb_interface.c
blob2d3415eea3a7d2ce176934cbe212507a1f6dda6f
1 /*
2 * Copyright (c) 2004-2007 Marcus Overhagen <marcus@overhagen.de>
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:
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
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.
25 #include <KernelExport.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include "dvb_interface.h"
29 #include "cx23882.h"
30 #include "cx23882_i2c.h"
31 #include "cx22702.h"
32 #include "dtt7592.h"
33 #include "driver.h"
34 #include "config.h"
35 #include "util.h"
37 #define TRACE_INTERFACE
38 #ifdef TRACE_INTERFACE
39 #define TRACE dprintf
40 #else
41 #define TRACE(a...)
42 #endif
45 #if 0
46 static void
47 dump_eeprom(cx23882_device *device)
49 uint8 d[256+8];
50 uint8 adr;
51 uint8 *p;
52 int i;
53 status_t res;
55 adr = 0;
56 res = i2c_xfer(device->i2c_bus, I2C_ADDR_EEPROM, &adr, 1, d, sizeof(d));
57 if (res != B_OK) {
58 TRACE("i2c_read failed: %08lx\n", res);
59 return;
61 for (p = d, i = 0; i < ((int)sizeof(d) / 8); i++, p+= 8)
62 TRACE("EEPROM %02x: %02x %02x %02x %02x %02x %02x %02x %02x\n", i * 8, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
65 #endif
68 status_t
69 interface_attach(void **cookie, const pci_info *info)
71 cx23882_device *device;
72 uint32 val;
73 int i;
75 TRACE("interface_attach\n");
77 device = malloc(sizeof(cx23882_device));
78 if (!device)
79 return B_NO_MEMORY;
80 *cookie = device;
82 // initialize cookie
83 memset(device, 0, sizeof(*device));
84 device->regs_area = -1;
85 device->dma_buf1_area = -1;
86 device->dma_buf2_area = -1;
87 device->capture_sem = -1;
89 device->pci_info = info;
91 // enable busmaster and memory mapped access, disable io port access
92 val = gPci->read_pci_config(device->pci_info->bus, device->pci_info->device, device->pci_info->function, PCI_command, 2);
93 val = PCI_PCICMD_BME | PCI_PCICMD_MSE | (val & ~PCI_PCICMD_IOS);
94 gPci->write_pci_config(device->pci_info->bus, device->pci_info->device, device->pci_info->function, PCI_command, 2, val);
96 // adjust PCI latency timer
97 val = gPci->read_pci_config(device->pci_info->bus, device->pci_info->device, device->pci_info->function, PCI_latency, 1);
98 TRACE("PCI latency is %02" B_PRIx32 ", changing to %02x\n", val,
99 PCI_LATENCY);
100 gPci->write_pci_config(device->pci_info->bus, device->pci_info->device, device->pci_info->function, PCI_latency, 1, PCI_LATENCY);
102 // get IRQ
103 device->irq = gPci->read_pci_config(device->pci_info->bus, device->pci_info->device, device->pci_info->function, PCI_interrupt_line, 1);
104 if (device->irq == 0 || device->irq == 0xff) {
105 dprintf("cx23882: Error, no IRQ assigned\n");
106 goto err;
108 TRACE("IRQ %d\n", device->irq);
110 // map registers into memory
111 val = gPci->read_pci_config(device->pci_info->bus, device->pci_info->device, device->pci_info->function, 0x10, 4);
112 val &= PCI_address_memory_32_mask;
113 if (val == 0) {
114 dprintf("cx23882: Error, no memory space assigned\n");
115 goto err;
117 TRACE("hardware register address 0x%" B_PRIx32 "\n", val);
118 device->regs_area = map_mem(&device->regs, (addr_t)val,
119 16777216 /* 16 MB */, 0, "cx23882 registers");
120 if (device->regs_area < B_OK) {
121 dprintf("cx23882: Error, can't map hardware registers\n");
122 goto err;
124 TRACE("mapped registers to %p\n", device->regs);
126 device->capture_sem = create_sem(0, "cx23882 capture");
128 cx23882_reset(device);
130 if (i2c_init(device) < B_OK) {
131 dprintf("cx23882: Error, can't init I2C\n");
135 if (cx23882_init(device) < B_OK) {
136 dprintf("cx23882: Error, can't init hardware\n");
140 for (i = 0; i < 20; i++)
141 if (cx22702_init(device->i2c_bus) == B_OK)
142 break;
143 if (i == 20) {
144 TRACE("cx22702_init failed\n");
145 goto err;
148 // setup interrupt handler
149 if (install_io_interrupt_handler(device->irq, cx23882_int, device, 0) < B_OK) {
150 dprintf("cx23882: Error, can't install interrupt handler\n");
151 goto err;
154 // dump_eeprom(device);
155 // dtt7582_test(device->i2c_bus);
157 return B_OK;
158 err:
159 free(cookie);
160 return B_ERROR;
164 void
165 interface_detach(void *cookie)
167 cx23882_device *device = cookie;
169 i2c_terminate(device);
171 if (cx23882_terminate(device) < B_OK) {
174 remove_io_interrupt_handler(device->irq, cx23882_int, device);
176 delete_area(device->regs_area);
178 delete_sem(device->capture_sem);
180 TRACE("interface_detach\n");
184 static void
185 interface_get_interface_info(dvb_interface_info_t *info)
187 memset(info, 0, sizeof(*info));
188 info->version = 1;
189 info->flags = 0;
190 info->type = DVB_TYPE_DVB_T;
191 strcpy(info->name, "CX23882");
192 strcpy(info->info, "Hauppauge WinTV-NOVA-T model 928 driver, Copyright (c) 2005 Marcus Overhagen");
196 status_t
197 interface_ioctl(void *cookie, uint32 op, void *arg, size_t len)
199 cx23882_device *device = cookie;
200 status_t res;
202 switch (op) {
203 case DVB_GET_INTERFACE_INFO:
205 dvb_interface_info_t info;
206 interface_get_interface_info(&info);
207 if (user_memcpy(arg, &info, sizeof(info)) < B_OK)
208 return B_BAD_ADDRESS;
209 break;
212 case DVB_GET_FREQUENCY_INFO:
214 dvb_frequency_info_t info;
215 if ((res = cx22702_get_frequency_info(device->i2c_bus, &info)) < B_OK)
216 return res;
217 if (user_memcpy(arg, &info, sizeof(info)) < B_OK)
218 return B_BAD_ADDRESS;
219 break;
222 case DVB_START_CAPTURE:
224 return cx23882_start_capture(device);
227 case DVB_STOP_CAPTURE:
229 return cx23882_stop_capture(device);
232 case DVB_SET_TUNING_PARAMETERS:
234 dvb_tuning_parameters_t params;
235 if (user_memcpy(&params, arg, sizeof(params)) < B_OK)
236 return B_BAD_ADDRESS;
237 if ((res = cx22702_set_tuning_parameters(device->i2c_bus, &params.u.dvb_t)) < B_OK)
238 return res;
239 break;
242 case DVB_GET_TUNING_PARAMETERS:
244 dvb_tuning_parameters_t params;
245 if ((res = cx22702_get_tuning_parameters(device->i2c_bus, &params.u.dvb_t)) < B_OK)
246 return res;
247 if (user_memcpy(arg, &params, sizeof(params)) < B_OK)
248 return B_BAD_ADDRESS;
249 break;
252 case DVB_GET_STATUS:
254 dvb_status_t status;
255 if ((res = cx22702_get_status(device->i2c_bus, &status)) < B_OK)
256 return res;
257 if (user_memcpy(arg, &status, sizeof(status)) < B_OK)
258 return B_BAD_ADDRESS;
259 break;
262 case DVB_GET_SS:
264 uint32 value;
265 if ((res = cx22702_get_ss(device->i2c_bus, &value)) < B_OK)
266 return res;
267 if (user_memcpy(arg, &value, sizeof(value)) < B_OK)
268 return B_BAD_ADDRESS;
269 break;
272 case DVB_GET_BER:
274 uint32 value;
275 if ((res = cx22702_get_ber(device->i2c_bus, &value)) < B_OK)
276 return res;
277 if (user_memcpy(arg, &value, sizeof(value)) < B_OK)
278 return B_BAD_ADDRESS;
279 break;
282 case DVB_GET_SNR:
284 uint32 value;
285 if ((res = cx22702_get_snr(device->i2c_bus, &value)) < B_OK)
286 return res;
287 if (user_memcpy(arg, &value, sizeof(value)) < B_OK)
288 return B_BAD_ADDRESS;
289 break;
292 case DVB_GET_UPC:
294 uint32 value;
295 if ((res = cx22702_get_upc(device->i2c_bus, &value)) < B_OK)
296 return res;
297 if (user_memcpy(arg, &value, sizeof(value)) < B_OK)
298 return B_BAD_ADDRESS;
299 break;
302 case DVB_CAPTURE:
304 dvb_capture_t cap_data;
305 // wait for data ready interrupt, with 100 ms timeout (in case tuning failed, bad reception, etc)
306 if ((res = acquire_sem_etc(device->capture_sem, 1, B_CAN_INTERRUPT | B_RELATIVE_TIMEOUT, 100000)) < B_OK)
307 return res;
308 cap_data.data = device->capture_data;
309 cap_data.size = device->capture_size;
310 cap_data.end_time = device->capture_end_time;
311 if (user_memcpy(arg, &cap_data, sizeof(cap_data)) < B_OK)
312 return B_BAD_ADDRESS;
313 break;
316 default:
318 TRACE("interface_ioctl\n");
319 return B_BAD_VALUE;
323 return B_OK;