vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / media / media-add-ons / usb_webcam / CamDevice.cpp
blob81d83fba029e2bd58ccb98cce0fbd9e88f94212d
1 /*
2 * Copyright 2004-2008, François Revol, <revol@free.fr>.
3 * Distributed under the terms of the MIT License.
4 */
7 #include "CamDevice.h"
8 #include "CamSensor.h"
9 #include "CamDeframer.h"
10 #include "CamDebug.h"
11 #include "AddOn.h"
13 #include <OS.h>
14 #include <Autolock.h>
16 //#define DEBUG_WRITE_DUMP
17 //#define DEBUG_DISCARD_DATA
18 //#define DEBUG_READ_DUMP
19 //#define DEBUG_DISCARD_INPUT
21 #undef B_WEBCAM_DECLARE_SENSOR
22 #define B_WEBCAM_DECLARE_SENSOR(sensorclass,sensorname) \
23 extern "C" CamSensor *Instantiate##sensorclass(CamDevice *cam);
24 #include "CamInternalSensors.h"
25 #undef B_WEBCAM_DECLARE_SENSOR
26 typedef CamSensor *(*SensorInstFunc)(CamDevice *cam);
27 struct { const char *name; SensorInstFunc instfunc; } kSensorTable[] = {
28 #define B_WEBCAM_DECLARE_SENSOR(sensorclass,sensorname) \
29 { #sensorname, &Instantiate##sensorclass },
30 #include "CamInternalSensors.h"
31 { NULL, NULL },
33 #undef B_WEBCAM_DECLARE_SENSOR
36 CamDevice::CamDevice(CamDeviceAddon &_addon, BUSBDevice* _device)
37 : fInitStatus(B_NO_INIT),
38 fSensor(NULL),
39 fBulkIn(NULL),
40 fIsoIn(NULL),
41 fLastParameterChanges(0),
42 fCamDeviceAddon(_addon),
43 fDevice(_device),
44 fSupportedDeviceIndex(-1),
45 fChipIsBigEndian(false),
46 fTransferEnabled(false),
47 fLocker("WebcamDeviceLock")
49 // fill in the generic flavor
50 memset(&fFlavorInfo, 0, sizeof(fFlavorInfo));
51 _addon.WebCamAddOn()->FillDefaultFlavorInfo(&fFlavorInfo);
52 // if we use id matching, cache the index to the list
53 if (fCamDeviceAddon.SupportedDevices()) {
54 fSupportedDeviceIndex = fCamDeviceAddon.Sniff(_device);
55 fFlavorInfoNameStr = "";
56 fFlavorInfoNameStr << fCamDeviceAddon.SupportedDevices()[fSupportedDeviceIndex].vendor << " USB Webcam";
57 fFlavorInfoInfoStr = "";
58 fFlavorInfoInfoStr << fCamDeviceAddon.SupportedDevices()[fSupportedDeviceIndex].vendor;
59 fFlavorInfoInfoStr << " (" << fCamDeviceAddon.SupportedDevices()[fSupportedDeviceIndex].product << ") USB Webcam";
60 fFlavorInfo.name = (char *)fFlavorInfoNameStr.String();
61 fFlavorInfo.info = (char *)fFlavorInfoInfoStr.String();
63 #ifdef DEBUG_WRITE_DUMP
64 fDumpFD = open("/boot/home/webcam.out", O_CREAT|O_RDWR, 0644);
65 #endif
66 #ifdef DEBUG_READ_DUMP
67 fDumpFD = open("/boot/home/webcam.out", O_RDONLY, 0644);
68 #endif
69 fBufferLen = 1*B_PAGE_SIZE;
70 fBuffer = (uint8 *)malloc(fBufferLen);
74 CamDevice::~CamDevice()
76 close(fDumpFD);
77 free(fBuffer);
78 if (fDeframer)
79 delete fDeframer;
83 status_t
84 CamDevice::InitCheck()
86 return fInitStatus;
90 bool
91 CamDevice::Matches(BUSBDevice* _device)
93 return _device == fDevice;
97 BUSBDevice*
98 CamDevice::GetDevice()
100 return fDevice;
104 void
105 CamDevice::Unplugged()
107 fDevice = NULL;
108 fBulkIn = NULL;
109 fIsoIn = NULL;
113 bool
114 CamDevice::IsPlugged()
116 return (fDevice != NULL);
120 const char *
121 CamDevice::BrandName()
123 if (fCamDeviceAddon.SupportedDevices() && (fSupportedDeviceIndex > -1))
124 return fCamDeviceAddon.SupportedDevices()[fSupportedDeviceIndex].vendor;
125 return "<unknown>";
129 const char *
130 CamDevice::ModelName()
132 if (fCamDeviceAddon.SupportedDevices() && (fSupportedDeviceIndex > -1))
133 return fCamDeviceAddon.SupportedDevices()[fSupportedDeviceIndex].product;
134 return "<unknown>";
138 bool
139 CamDevice::SupportsBulk()
141 return false;
145 bool
146 CamDevice::SupportsIsochronous()
148 return false;
152 status_t
153 CamDevice::StartTransfer()
155 status_t err = B_OK;
156 PRINT((CH "()" CT));
157 if (fTransferEnabled)
158 return EALREADY;
159 fPumpThread = spawn_thread(_DataPumpThread, "USB Webcam Data Pump", 50,
160 this);
161 if (fPumpThread < B_OK)
162 return fPumpThread;
163 if (fSensor)
164 err = fSensor->StartTransfer();
165 if (err < B_OK)
166 return err;
167 fTransferEnabled = true;
168 resume_thread(fPumpThread);
169 PRINT((CH ": transfer enabled" CT));
170 return B_OK;
174 status_t
175 CamDevice::StopTransfer()
177 status_t err = B_OK;
178 PRINT((CH "()" CT));
179 if (!fTransferEnabled)
180 return EALREADY;
181 if (fSensor)
182 err = fSensor->StopTransfer();
183 if (err < B_OK)
184 return err;
185 fTransferEnabled = false;
187 // the thread itself might Lock()
188 fLocker.Unlock();
189 wait_for_thread(fPumpThread, &err);
190 fLocker.Lock();
192 return B_OK;
196 status_t
197 CamDevice::SuggestVideoFrame(uint32 &width, uint32 &height)
199 if (Sensor()) {
200 width = Sensor()->MaxWidth();
201 height = Sensor()->MaxHeight();
202 return B_OK;
204 return B_NO_INIT;
208 status_t
209 CamDevice::AcceptVideoFrame(uint32 &width, uint32 &height)
211 status_t err = ENOSYS;
212 if (Sensor())
213 err = Sensor()->AcceptVideoFrame(width, height);
214 if (err < B_OK)
215 return err;
216 SetVideoFrame(BRect(0, 0, width - 1, height - 1));
217 return B_OK;
221 status_t
222 CamDevice::SetVideoFrame(BRect frame)
224 fVideoFrame = frame;
225 return B_OK;
229 status_t
230 CamDevice::SetScale(float scale)
232 return B_OK;
236 status_t
237 CamDevice::SetVideoParams(float brightness, float contrast, float hue,
238 float red, float green, float blue)
240 return B_OK;
244 void
245 CamDevice::AddParameters(BParameterGroup *group, int32 &index)
247 fFirstParameterID = index;
251 status_t
252 CamDevice::GetParameterValue(int32 id, bigtime_t *last_change, void *value,
253 size_t *size)
255 return B_BAD_VALUE;
259 status_t
260 CamDevice::SetParameterValue(int32 id, bigtime_t when, const void *value,
261 size_t size)
263 return B_BAD_VALUE;
267 size_t
268 CamDevice::MinRawFrameSize()
270 return 0;
274 size_t
275 CamDevice::MaxRawFrameSize()
277 return 0;
281 bool
282 CamDevice::ValidateStartOfFrameTag(const uint8 *tag, size_t taglen)
284 return true;
288 bool
289 CamDevice::ValidateEndOfFrameTag(const uint8 *tag, size_t taglen,
290 size_t datalen)
292 return true;
296 status_t
297 CamDevice::WaitFrame(bigtime_t timeout)
299 if (fDeframer)
300 return WaitFrame(timeout);
301 return EINVAL;
305 status_t
306 CamDevice::GetFrameBitmap(BBitmap **bm, bigtime_t *stamp)
308 return EINVAL;
312 status_t
313 CamDevice::FillFrameBuffer(BBuffer *buffer, bigtime_t *stamp)
315 return EINVAL;
319 bool
320 CamDevice::Lock()
322 return fLocker.Lock();
326 status_t
327 CamDevice::PowerOnSensor(bool on)
329 return B_OK;
333 ssize_t
334 CamDevice::WriteReg(uint16 address, uint8 *data, size_t count)
336 return ENOSYS;
340 ssize_t
341 CamDevice::WriteReg8(uint16 address, uint8 data)
343 return WriteReg(address, &data, sizeof(uint8));
347 ssize_t
348 CamDevice::WriteReg16(uint16 address, uint16 data)
350 if (fChipIsBigEndian)
351 data = B_HOST_TO_BENDIAN_INT16(data);
352 else
353 data = B_HOST_TO_LENDIAN_INT16(data);
354 return WriteReg(address, (uint8 *)&data, sizeof(uint16));
358 ssize_t
359 CamDevice::ReadReg(uint16 address, uint8 *data, size_t count, bool cached)
361 return ENOSYS;
365 ssize_t
366 CamDevice::OrReg8(uint16 address, uint8 data, uint8 mask)
368 uint8 value;
369 if (ReadReg(address, &value, 1, true) < 1)
370 return EIO;
371 value &= mask;
372 value |= data;
373 return WriteReg8(address, value);
377 ssize_t
378 CamDevice::AndReg8(uint16 address, uint8 data)
380 uint8 value;
381 if (ReadReg(address, &value, 1, true) < 1)
382 return EIO;
383 value &= data;
384 return WriteReg8(address, value);
389 status_t
390 CamDevice::GetStatusIIC()
392 return ENOSYS;
396 /*status_t
397 CamDevice::WaitReadyIIC()
399 return ENOSYS;
403 ssize_t
404 CamDevice::WriteIIC(uint8 address, uint8 *data, size_t count)
406 return ENOSYS;
410 ssize_t
411 CamDevice::WriteIIC8(uint8 address, uint8 data)
413 return WriteIIC(address, &data, 1);
417 ssize_t
418 CamDevice::WriteIIC16(uint8 address, uint16 data)
420 if (Sensor() && Sensor()->IsBigEndian())
421 data = B_HOST_TO_BENDIAN_INT16(data);
422 else
423 data = B_HOST_TO_LENDIAN_INT16(data);
424 return WriteIIC(address, (uint8 *)&data, 2);
428 ssize_t
429 CamDevice::ReadIIC(uint8 address, uint8 *data)
431 //TODO: make it mode generic
432 return ENOSYS;
436 ssize_t
437 CamDevice::ReadIIC8(uint8 address, uint8 *data)
439 return ReadIIC(address, data);
443 ssize_t
444 CamDevice::ReadIIC16(uint8 address, uint16 *data)
446 return ENOSYS;
450 status_t
451 CamDevice::SetIICBitsMode(size_t bits)
453 return ENOSYS;
457 status_t
458 CamDevice::ProbeSensor()
460 const usb_webcam_support_descriptor *devs;
461 const usb_webcam_support_descriptor *dev = NULL;
462 status_t err;
463 int32 i;
465 PRINT((CH ": probing sensors..." CT));
466 if (fCamDeviceAddon.SupportedDevices() == NULL)
467 return B_ERROR;
468 devs = fCamDeviceAddon.SupportedDevices();
469 for (i = 0; devs[i].vendor; i++) {
470 if (GetDevice()->VendorID() != devs[i].desc.vendor)
471 continue;
472 if (GetDevice()->ProductID() != devs[i].desc.product)
473 continue;
474 dev = &devs[i];
475 break;
477 if (!dev)
478 return ENODEV;
479 if (!dev->sensors) // no usable sensor
480 return ENOENT;
481 BString sensors(dev->sensors);
482 for (i = 0; i > -1 && i < sensors.Length(); ) {
483 BString name;
484 sensors.CopyInto(name, i, sensors.FindFirst(',', i) - i);
485 PRINT((CH ": probing sensor '%s'..." CT, name.String()));
487 fSensor = CreateSensor(name.String());
488 if (fSensor) {
489 err = fSensor->Probe();
490 if (err >= B_OK)
491 return B_OK;
493 PRINT((CH ": sensor '%s' Probe: %s" CT, name.String(),
494 strerror(err)));
496 delete fSensor;
497 fSensor = NULL;
500 i = sensors.FindFirst(',', i+1);
501 if (i > - 1)
502 i++;
504 return ENOENT;
508 CamSensor *
509 CamDevice::CreateSensor(const char *name)
511 for (int32 i = 0; kSensorTable[i].name; i++) {
512 if (!strcmp(kSensorTable[i].name, name))
513 return kSensorTable[i].instfunc(this);
515 PRINT((CH ": sensor '%s' not found" CT, name));
516 return NULL;
520 void
521 CamDevice::SetDataInput(BDataIO *input)
523 fDataInput = input;
527 status_t
528 CamDevice::DataPumpThread()
530 if (SupportsBulk()) {
531 PRINT((CH ": using Bulk" CT));
532 while (fTransferEnabled) {
533 ssize_t len = -1;
534 BAutolock lock(fLocker);
535 if (!lock.IsLocked())
536 break;
537 if (!fBulkIn)
538 break;
539 #ifndef DEBUG_DISCARD_INPUT
540 len = fBulkIn->BulkTransfer(fBuffer, fBufferLen);
541 #endif
543 //PRINT((CH ": got %ld bytes" CT, len));
544 #ifdef DEBUG_WRITE_DUMP
545 write(fDumpFD, fBuffer, len);
546 #endif
547 #ifdef DEBUG_READ_DUMP
548 if ((len = read(fDumpFD, fBuffer, fBufferLen)) < fBufferLen)
549 lseek(fDumpFD, 0LL, SEEK_SET);
550 #endif
552 if (len <= 0) {
553 PRINT((CH ": BulkIn: %s" CT, strerror(len)));
554 break;
557 #ifndef DEBUG_DISCARD_DATA
558 if (fDataInput) {
559 fDataInput->Write(fBuffer, len);
560 // else drop
562 #endif
563 //snooze(2000);
566 #ifdef SUPPORT_ISO
567 else if (SupportsIsochronous()) {
568 int numPacketDescriptors = 16;
569 usb_iso_packet_descriptor packetDescriptors[numPacketDescriptors];
571 // Initialize packetDescriptor request lengths
572 for (int i = 0; i<numPacketDescriptors; i++)
573 packetDescriptors[i].request_length = 256;
575 int fullPackets = 0;
576 int totalPackets = 0;
577 while (fTransferEnabled) {
578 ssize_t len = -1;
579 BAutolock lock(fLocker);
580 if (!lock.IsLocked())
581 break;
582 if (!fIsoIn)
583 break;
584 #ifndef DEBUG_DISCARD_INPUT
585 len = fIsoIn->IsochronousTransfer(fBuffer, fBufferLen, packetDescriptors,
586 numPacketDescriptors);
587 #endif
589 //PRINT((CH ": got %d bytes" CT, len));
590 #ifdef DEBUG_WRITE_DUMP
591 write(fDumpFD, fBuffer, len);
592 #endif
593 #ifdef DEBUG_READ_DUMP
594 if ((len = read(fDumpFD, fBuffer, fBufferLen)) < fBufferLen)
595 lseek(fDumpFD, 0LL, SEEK_SET);
596 #endif
598 if (len <= 0) {
599 PRINT((CH ": IsoIn: %s" CT, strerror(len)));
600 continue;
603 #ifndef DEBUG_DISCARD_DATA
604 if (fDataInput) {
605 int fBufferIndex = 0;
606 for (int i = 0; i < numPacketDescriptors; i++) {
607 int actual_length = ((usb_iso_packet_descriptor)
608 packetDescriptors[i]).actual_length;
609 if (actual_length > 0) {
610 fDataInput->Write(&fBuffer[fBufferIndex],
611 actual_length);
613 fBufferIndex += actual_length;
616 #endif
617 //snooze(2000);
620 #endif
621 else {
622 PRINT((CH ": No supported transport." CT));
623 return B_UNSUPPORTED;
625 return B_OK;
629 int32
630 CamDevice::_DataPumpThread(void *_this)
632 CamDevice *dev = (CamDevice *)_this;
633 return dev->DataPumpThread();
637 void
638 CamDevice::DumpRegs()
643 status_t
644 CamDevice::SendCommand(uint8 dir, uint8 request, uint16 value,
645 uint16 index, uint16 length, void* data)
647 ssize_t ret;
648 if (!GetDevice())
649 return ENODEV;
650 if (length > GetDevice()->MaxEndpoint0PacketSize())
651 return EINVAL;
652 ret = GetDevice()->ControlTransfer(
653 USB_REQTYPE_VENDOR | USB_REQTYPE_INTERFACE_OUT | dir,
654 request, value, index, length, data);
655 return ret;
659 CamDeviceAddon::CamDeviceAddon(WebCamMediaAddOn* webcam)
660 : fWebCamAddOn(webcam),
661 fSupportedDevices(NULL)
666 CamDeviceAddon::~CamDeviceAddon()
671 const char *
672 CamDeviceAddon::BrandName()
674 return "<unknown>";
678 status_t
679 CamDeviceAddon::Sniff(BUSBDevice *device)
681 PRINT((CH ": Sniffing for %s" CT, BrandName()));
682 if (!fSupportedDevices)
683 return ENODEV;
684 if (!device)
685 return EINVAL;
687 bool supported = false;
688 for (uint32 i = 0; !supported && fSupportedDevices[i].vendor; i++) {
689 if ((fSupportedDevices[i].desc.vendor != 0
690 && device->VendorID() != fSupportedDevices[i].desc.vendor)
691 || (fSupportedDevices[i].desc.product != 0
692 && device->ProductID() != fSupportedDevices[i].desc.product))
693 continue;
695 if ((fSupportedDevices[i].desc.dev_class == 0
696 || device->Class() == fSupportedDevices[i].desc.dev_class)
697 && (fSupportedDevices[i].desc.dev_subclass == 0
698 || device->Subclass() == fSupportedDevices[i].desc.dev_subclass)
699 && (fSupportedDevices[i].desc.dev_protocol == 0
700 || device->Protocol() == fSupportedDevices[i].desc.dev_protocol)) {
701 supported = true;
704 #ifdef __HAIKU__
705 // we have to check all interfaces for matching class/subclass/protocol
706 for (uint32 j = 0; !supported && j < device->CountConfigurations(); j++) {
707 const BUSBConfiguration* cfg = device->ConfigurationAt(j);
708 for (uint32 k = 0; !supported && k < cfg->CountInterfaces(); k++) {
709 const BUSBInterface* intf = cfg->InterfaceAt(k);
710 for (uint32 l = 0; !supported && l < intf->CountAlternates(); l++) {
711 const BUSBInterface* alt = intf->AlternateAt(l);
712 if ((fSupportedDevices[i].desc.dev_class == 0
713 || alt->Class() == fSupportedDevices[i].desc.dev_class)
714 && (fSupportedDevices[i].desc.dev_subclass == 0
715 || alt->Subclass() == fSupportedDevices[i].desc.dev_subclass)
716 && (fSupportedDevices[i].desc.dev_protocol == 0
717 || alt->Protocol() == fSupportedDevices[i].desc.dev_protocol)) {
718 supported = true;
723 #endif
725 if (supported)
726 return i;
729 return ENODEV;
733 CamDevice *
734 CamDeviceAddon::Instantiate(CamRoster &roster, BUSBDevice *from)
736 return NULL;
740 void
741 CamDeviceAddon::SetSupportedDevices(const usb_webcam_support_descriptor *devs)
743 fSupportedDevices = devs;