xref: /haiku/src/add-ons/media/media-add-ons/usb_webcam/addons/sonix/SonixCamDevice.cpp (revision 302f62604763c95777d6d04cca456e876f471c4f)
1 #include "SonixCamDevice.h"
2 #include "CamDebug.h"
3 #include "CamSensor.h"
4 #include "CamBufferingDeframer.h"
5 #include "CamStreamingDeframer.h"
6 
7 #include <usb/USBDevice.h>
8 #include <usb/USBConfiguration.h>
9 #include <usb/USBInterface.h>
10 
11 #include <interface/Bitmap.h>
12 #include <media/Buffer.h>
13 
14 const usb_named_support_descriptor kSupportedDevices[] = {
15 {{ 0, 0, 0, 0x0c45, 0x6005 }, "Sonix", "Sonix"},
16 {{ 0, 0, 0, 0x0c45, 0x6009 }, "Trust", "spacec@m 120" },
17 {{ 0, 0, 0, 0x0c45, 0x600D }, "Trust", "spacec@m 120" },
18 {{ 0, 0, 0, 0, 0}, NULL, NULL }
19 };
20 
21 // 12 bytes actually
22 static const uint8 sof_mark_1[] = { 0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x00 };
23 static const uint8 sof_mark_2[] = { 0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x01 };
24 static const uint8 *sof_marks[] = { sof_mark_1, sof_mark_2 };
25 
26 static const uint8 eof_mark_1[] = { 0x00, 0x00, 0x00, 0x00 };
27 static const uint8 eof_mark_2[] = { 0x40, 0x00, 0x00, 0x00 };
28 static const uint8 eof_mark_3[] = { 0x80, 0x00, 0x00, 0x00 };
29 static const uint8 eof_mark_4[] = { 0xc0, 0x00, 0x00, 0x00 };
30 static const uint8 *eof_marks[] = { eof_mark_1, eof_mark_2, eof_mark_3, eof_mark_4 };
31 
32 void bayer2rgb24(unsigned char *dst, unsigned char *src, long int WIDTH, long int HEIGHT);
33 void bayer2rgb32le(unsigned char *dst, unsigned char *src, long int WIDTH, long int HEIGHT);
34 
35 // -----------------------------------------------------------------------------
36 SonixCamDevice::SonixCamDevice(CamDeviceAddon &_addon, BUSBDevice* _device)
37           :CamDevice(_addon, _device)
38 {
39 	uchar data[8]; /* store bytes returned from sonix commands */
40 	status_t err;
41 	fFrameTagState = 0;
42 
43 	memset(fCachedRegs, 0, SN9C102_REG_COUNT);
44 	fChipVersion = 2;
45 	if ((GetDevice()->ProductID() & ~0x3F) == 0x6080) {
46 		fChipVersion = 3; // says V4L2
47 	}
48 	switch (GetDevice()->ProductID()) {
49 	case 0x6001:
50 	case 0x6005:
51 	case 0x60ab:
52 		fSensor = CreateSensor("tas5110c1b");
53 		break;
54 	default:
55 		break;
56 	}
57 
58 //	fDeframer = new CamBufferingDeframer(this);
59 	fDeframer = new CamStreamingDeframer(this);
60 	fDeframer->RegisterSOFTags(sof_marks, 2, sizeof(sof_mark_1), 12);
61 	fDeframer->RegisterEOFTags(eof_marks, 4, sizeof(eof_mark_1), sizeof(eof_mark_1));
62 	SetDataInput(fDeframer);
63 
64 	/* init hw */
65 
66 	const BUSBConfiguration *config = GetDevice()->ConfigurationAt(0);
67 	if (config) {
68 		const BUSBInterface *inter = config->InterfaceAt(0);
69 		int i;
70 
71 		GetDevice()->SetConfiguration(config);
72 
73 		for (i = 0; inter && (i < inter->CountEndpoints()); i++) {
74 			const BUSBEndpoint *e = inter->EndpointAt(i);
75 			if (e && e->IsBulk() && e->IsInput()) {
76 				fBulkIn = e;
77 				PRINT((CH ": Using inter[0].endpoint[%d]; maxpktsz: %d" CT, i, e->MaxPacketSize()));
78 				break;
79 			}
80 		}
81 
82 	}
83 
84 	/* sanity check */
85 	err = ReadReg(SN9C102_ASIC_ID, data);
86 	if (err < 0 || data[0] != 0x10) {
87 		PRINT((CH ": BAD ASIC signature! (%u != %u)" CT, data[0], 0x10));
88 		return;
89 	}
90 
91 
92 	if (Sensor()) {
93 		PRINT((CH ": CamSensor: %s" CT, Sensor()->Name()));
94 		fInitStatus = Sensor()->Setup();
95 //		SetVideoFrame(BRect(0, 0, Sensor()->MaxWidth()-1, Sensor()->MaxHeight()-1));
96 //		SetVideoFrame(BRect(0, 0, 320-1, 240-1));
97 	}
98 	//SetScale(1);
99 }
100 
101 // -----------------------------------------------------------------------------
102 SonixCamDevice::~SonixCamDevice()
103 {
104 	if (Sensor())
105 		delete fSensor;
106 	fSensor = NULL;
107 }
108 
109 // -----------------------------------------------------------------------------
110 bool
111 SonixCamDevice::SupportsBulk()
112 {
113 	return true;
114 }
115 
116 // -----------------------------------------------------------------------------
117 bool
118 SonixCamDevice::SupportsIsochronous()
119 {
120 	return true;
121 }
122 
123 // -----------------------------------------------------------------------------
124 status_t
125 SonixCamDevice::StartTransfer()
126 {
127 	status_t err;
128 	uint8 r;
129 
130 	SetScale(1);
131 	if (Sensor())
132 		SetVideoFrame(BRect(0, 0, Sensor()->MaxWidth()-1, Sensor()->MaxHeight()-1));
133 
134 	SetVideoFrame(BRect(0, 0, 320-1, 240-1));
135 
136 DumpRegs();
137 	err = ReadReg(SN9C102_CHIP_CTRL, &r, 1, true);
138 	if (err < 0)
139 		return err;
140 	r |= 0x04;
141 	err = WriteReg8(SN9C102_CHIP_CTRL, r);
142 	if (err < 0)
143 		return err;
144 	return CamDevice::StartTransfer();
145 }
146 
147 // -----------------------------------------------------------------------------
148 status_t
149 SonixCamDevice::StopTransfer()
150 {
151 	status_t err;
152 	uint8 r;
153 
154 DumpRegs();
155 	err = CamDevice::StopTransfer();
156 //	if (err < 0)
157 //		return err;
158 	err = ReadReg(SN9C102_CHIP_CTRL, &r, 1, true);
159 	if (err < 0)
160 		return err;
161 	r &= ~0x04;
162 	err = WriteReg8(SN9C102_CHIP_CTRL, r);
163 	if (err < 0)
164 		return err;
165 	return err;
166 }
167 
168 // -----------------------------------------------------------------------------
169 ssize_t
170 SonixCamDevice::WriteReg(uint16 address, uint8 *data, size_t count)
171 {
172 	PRINT((CH "(%u, @%p, %u)" CT, address, data, count));
173 	if (address + count > SN9C102_REG_COUNT) {
174 		PRINT((CH ": Invalid register range [%u;%u]" CT, address, address+count));
175 		return EINVAL;
176 	}
177 	memcpy(&fCachedRegs[address], data, count);
178 	return SendCommand(USB_REQTYPE_DEVICE_OUT, 0x08, address, 0, count, data);
179 }
180 
181 // -----------------------------------------------------------------------------
182 ssize_t
183 SonixCamDevice::ReadReg(uint16 address, uint8 *data, size_t count, bool cached)
184 {
185 	PRINT((CH "(%u, @%p, %u, %d)" CT, address, data, count, cached));
186 	if (address + count > SN9C102_REG_COUNT) {
187 		PRINT((CH ": Invalid register range [%u;%u]" CT, address, address+count));
188 		return EINVAL;
189 	}
190 	if (cached) {
191 		memcpy(data, &fCachedRegs[address], count);
192 		return count;
193 	}
194 	return SendCommand(USB_REQTYPE_DEVICE_IN, 0x00, address, 0, count, data);
195 }
196 
197 // -----------------------------------------------------------------------------
198 status_t
199 SonixCamDevice::GetStatusIIC()
200 {
201 	status_t err;
202 	uint8 status = 0;
203 	err = ReadReg(SN9C102_I2C_SETUP, &status);
204 	//dprintf(ID "i2c_status: error 0x%08lx, status = %02x\n", err, status);
205 	if (err < 0)
206 		return err;
207 	return (status&0x08)?EIO:0;
208 }
209 
210 // -----------------------------------------------------------------------------
211 status_t
212 SonixCamDevice::WaitReadyIIC()
213 {
214 	status_t err;
215 	uint8 status = 0;
216 	int tries = 5;
217 	if (!Sensor())
218 		return B_NO_INIT;
219 	while (tries--) {
220 		err = ReadReg(SN9C102_I2C_SETUP, &status);
221 		//dprintf(ID "i2c_wait_ready: error 0x%08lx, status = %02x\n", err, status);
222 		if (err < 0) return err;
223 		if (status & 0x04) return B_OK;
224 		//XXX:FIXME:spin((1+5+11*dev->sensor->use_400kHz)*8);
225 		snooze((1+5+11*Sensor()->Use400kHz())*8);
226 	}
227 	return EBUSY;
228 }
229 
230 // -----------------------------------------------------------------------------
231 ssize_t
232 SonixCamDevice::WriteIIC(uint8 address, uint8 *data, size_t count)
233 {
234 	status_t err;
235 	uint8 status;
236 	uint8 buffer[8];
237 	if (!Sensor())
238 		return B_NO_INIT;
239 	//dprintf(ID "sonix_i2c_write_multi(, %02x, %d, {%02x, %02x, %02x, %02x, %02x})\n", slave, count, d0, d1, d2, d3, d4);
240 	count++; // includes address
241 	if (count > 5)
242 		return EINVAL;
243 	buffer[0] = (count << 4) | Sensor()->Use400kHz()?0x01:0
244 							 | Sensor()->UseRealIIC()?0x80:0;
245 	buffer[1] = Sensor()->IICWriteAddress();
246 	buffer[2] = address;
247 	memset(&buffer[3], 0, 5);
248 	memcpy(&buffer[3], data, count);
249 	buffer[7] = 0x14; /* absolutely no idea why V4L2 driver use that value */
250 	err = WriteReg(SN9C102_I2C_SETUP, buffer, 8);
251 	//dprintf(ID "sonix_i2c_write_multi: set_regs error 0x%08lx\n", err);
252 	//PRINT((CH ": WriteReg: %s" CT, strerror(err)));
253 	if (err < 0) return err;
254 	err = WaitReadyIIC();
255 	//dprintf(ID "sonix_i2c_write_multi: sonix_i2c_wait_ready error 0x%08lx\n", err);
256 	//PRINT((CH ": Wait: %s" CT, strerror(err)));
257 	if (err) return err;
258 	err = GetStatusIIC();
259 	//dprintf(ID "sonix_i2c_write_multi: sonix_i2c_status error 0x%08lx\n", err);
260 	//PRINT((CH ": Status: %s" CT, strerror(err)));
261 	if (err) return err;
262 	//dprintf(ID "sonix_i2c_write_multi: succeeded\n");
263 	PRINT((CH ": success" CT));
264 	return B_OK;
265 }
266 
267 // -----------------------------------------------------------------------------
268 ssize_t
269 SonixCamDevice::ReadIIC(uint8 address, uint8 *data)
270 {
271 	status_t err, lasterr = B_OK;
272 	uint8 status;
273 	uint8 buffer[8];
274 	if (!Sensor())
275 		return B_NO_INIT;
276 	//dprintf(ID "sonix_i2c_write_multi(, %02x, %d, {%02x, %02x, %02x, %02x, %02x})\n", slave, count, d0, d1, d2, d3, d4);
277 	buffer[0] = (1 << 4) | Sensor()->Use400kHz()?0x01:0
278 						 | Sensor()->UseRealIIC()?0x80:0;
279 	buffer[1] = Sensor()->IICWriteAddress();
280 	buffer[2] = address;
281 	buffer[7] = 0x10; /* absolutely no idea why V4L2 driver use that value */
282 	err = WriteReg(SN9C102_I2C_SETUP, buffer, 8);
283 	//dprintf(ID "sonix_i2c_write_multi: set_regs error 0x%08lx\n", err);
284 	if (err) return err;
285 	err = WaitReadyIIC();
286 	//dprintf(ID "sonix_i2c_write_multi: sonix_i2c_wait_ready error 0x%08lx\n", err);
287 	//if (err) return err;
288 
289 
290 	//dprintf(ID "sonix_i2c_write_multi(, %02x, %d, {%02x, %02x, %02x, %02x, %02x})\n", slave, count, d0, d1, d2, d3, d4);
291 	buffer[0] = (1 << 4) | Sensor()->Use400kHz()?0x01:0
292 				  | 0x02 | Sensor()->UseRealIIC()?0x80:0; /* read 1 byte */
293 	buffer[1] = Sensor()->IICReadAddress();//IICWriteAddress
294 	buffer[7] = 0x10; /* absolutely no idea why V4L2 driver use that value */
295 	err = WriteReg(SN9C102_I2C_SETUP, buffer, 8);
296 	//dprintf(ID "sonix_i2c_write_multi: set_regs error 0x%08lx\n", err);
297 	if (err) return err;
298 	err = WaitReadyIIC();
299 	//dprintf(ID "sonix_i2c_write_multi: sonix_i2c_wait_ready error 0x%08lx\n", err);
300 	if (err) return err;
301 
302 	err = ReadReg(SN9C102_I2C_DATA0, buffer, 5);
303 	if (err) lasterr = err;
304 
305 	err = GetStatusIIC();
306 	//dprintf(ID "sonix_i2c_write_multi: sonix_i2c_status error 0x%08lx\n", err);
307 	if (err) return err;
308 	//dprintf(ID "sonix_i2c_write_multi: succeeded\n");
309 	if (lasterr) return err;
310 
311 	/* we should get what we want in buffer[4] according to the V4L2 driver...
312 	 * probably because the 5 bytes are a bit shift register?
313 	 */
314 	*data = buffer[4];
315 
316 	return 1;
317 }
318 
319 // -----------------------------------------------------------------------------
320 status_t
321 SonixCamDevice::SetVideoFrame(BRect frame)
322 {
323 	uint16 x, y, width, height;
324 	x = (uint16)frame.left;
325 	y = (uint16)frame.top;
326 	width = (uint16)(frame.right - frame.left + 1) / 16;
327 	height = (uint16)(frame.bottom - frame.top + 1) / 16;
328 	PRINT((CH "(%u, %u, %u, %u)" CT, x, y, width, height));
329 
330 	WriteReg8(SN9C102_H_START, x);
331 	WriteReg8(SN9C102_V_START, y);
332 	WriteReg8(SN9C102_H_SIZE, width);
333 	WriteReg8(SN9C102_V_SIZE, height);
334 	if (Sensor()) {
335 		Sensor()->SetVideoFrame(frame);
336 	}
337 	return CamDevice::SetVideoFrame(frame);
338 }
339 
340 // -----------------------------------------------------------------------------
341 status_t
342 SonixCamDevice::SetScale(float scale)
343 {
344 	status_t err;
345 	uint8 r;
346 	int iscale = (int)scale;
347 
348 	PRINT((CH "(%u)" CT, iscale));
349 	err = ReadReg(SN9C102_SYNC_N_SCALE, &r, 1, true);
350 	if (err < 0)
351 		return err;
352 	r &= ~0x30;
353 	switch (iscale) {
354 	case 1:
355 	case 2:
356 	case 4:
357 		r |= ((iscale-1) << 4);
358 		break;
359 	default:
360 		return EINVAL;
361 	}
362 	err = WriteReg8(SN9C102_SYNC_N_SCALE, r);
363 	return err;
364 }
365 
366 // -----------------------------------------------------------------------------
367 status_t
368 SonixCamDevice::SetVideoParams(float brightness, float contrast, float hue, float red, float green, float blue)
369 {
370 	return B_OK;
371 }
372 
373 // -----------------------------------------------------------------------------
374 size_t
375 SonixCamDevice::MinRawFrameSize()
376 {
377 	// if (fCompressionEnabled) { ... return ; }
378 	BRect vf(VideoFrame());
379 	int w = vf.IntegerWidth()+1;
380 	int h = vf.IntegerHeight()+1;
381 	// 1 byte/pixel
382 	return (size_t)(w*h);
383 }
384 
385 // -----------------------------------------------------------------------------
386 size_t
387 SonixCamDevice::MaxRawFrameSize()
388 {
389 	// if (fCompressionEnabled) { ... return ; }
390 	return MinRawFrameSize()+1024*0; // fixed size frame (uncompressed)
391 }
392 
393 // -----------------------------------------------------------------------------
394 bool
395 SonixCamDevice::ValidateStartOfFrameTag(const uint8 *tag, size_t taglen)
396 {
397 	// SOF come with an 00, 40, 80, C0 sequence,
398 	// supposedly corresponding with an equal byte in the end tag
399 	fFrameTagState = tag[7] & 0xC0;
400 	PRINT((CH "(, %d) state %x" CT, taglen, fFrameTagState));
401 
402 	// which seems to be the same as of the EOF tag
403 	return true;
404 }
405 
406 // -----------------------------------------------------------------------------
407 bool
408 SonixCamDevice::ValidateEndOfFrameTag(const uint8 *tag, size_t taglen, size_t datalen)
409 {
410 	//PRINT((CH "(, %d) %x == %x" CT, taglen, (tag[0] & 0xC0), fFrameTagState));
411 	// make sure the tag corresponds to the SOF we refer to
412 	if ((tag[0] & 0xC0) != fFrameTagState) {
413 		PRINT((CH ": discarded EOF %x != %x" CT, fFrameTagState, tag[0] & 0xC0));
414 		return false;
415 	}
416 	//PRINT((CH ": validated EOF %x, len %d" CT, fFrameTagState, datalen));
417 	return true;
418 }
419 
420 // -----------------------------------------------------------------------------
421 status_t
422 SonixCamDevice::GetFrameBitmap(BBitmap **bm)
423 {
424 	BBitmap *b;
425 	CamFrame *f;
426 	bigtime_t stamp;
427 	status_t err;
428 	PRINT((CH "()" CT));
429 	err = fDeframer->WaitFrame(200000);
430 	if (err < B_OK) { PRINT((CH ": WaitFrame: %s" CT, strerror(err))); }
431 	if (err < B_OK)
432 		return err;
433 	err = fDeframer->GetFrame(&f, &stamp);
434 	if (err < B_OK) { PRINT((CH ": GetFrame: %s" CT, strerror(err))); }
435 	if (err < B_OK)
436 		return err;
437 	PRINT((CH ": VideoFrame = %fx%f,%fx%f" CT, VideoFrame().left, VideoFrame().top, VideoFrame().right, VideoFrame().bottom));
438 
439 	long int w = VideoFrame().right - VideoFrame().left + 1;
440 	long int h = VideoFrame().bottom - VideoFrame().top + 1;
441 	b = new BBitmap(VideoFrame().OffsetToSelf(0,0), 0, B_RGB32, w*4);
442 	PRINT((CH ": Frame: %dx%d" CT, w, h));
443 
444 	bayer2rgb24((unsigned char *)b->Bits(), (unsigned char *)f->Buffer(), w, h);
445 
446 	PRINT((CH ": got 1 frame (len %d)" CT, b->BitsLength()));
447 	*bm = b;
448 	return B_OK;
449 }
450 
451 // -----------------------------------------------------------------------------
452 status_t
453 SonixCamDevice::FillFrameBuffer(BBuffer *buffer)
454 {
455 	CamFrame *f;
456 	bigtime_t stamp;
457 	status_t err;
458 	PRINT((CH "()" CT));
459 
460 	memset(buffer->Data(), 0, buffer->SizeAvailable());
461 	err = fDeframer->WaitFrame(2000000);
462 	if (err < B_OK) { PRINT((CH ": WaitFrame: %s" CT, strerror(err))); }
463 	if (err < B_OK)
464 		return err;
465 
466 	err = fDeframer->GetFrame(&f, &stamp);
467 	if (err < B_OK) { PRINT((CH ": GetFrame: %s" CT, strerror(err))); }
468 	if (err < B_OK)
469 		return err;
470 
471 	long int w = VideoFrame().right - VideoFrame().left + 1;
472 	long int h = VideoFrame().bottom - VideoFrame().top + 1;
473 	PRINT((CH ": VideoFrame = %fx%f,%fx%f Frame: %dx%d" CT, VideoFrame().left, VideoFrame().top, VideoFrame().right, VideoFrame().bottom, w, h));
474 
475 	if (buffer->SizeAvailable() >= w*h*4)
476 		bayer2rgb32le((unsigned char *)buffer->Data(), (unsigned char *)f->Buffer(), w, h);
477 
478 	delete f;
479 
480 	PRINT((CH ": available %d, required %d" CT, buffer->SizeAvailable(), w*h*4));
481 	if (buffer->SizeAvailable() < w*h*4)
482 		return E2BIG;
483 	PRINT((CH ": got 1 frame (len %d)" CT, buffer->SizeUsed()));
484 	return B_OK;
485 }
486 
487 // -----------------------------------------------------------------------------
488 void
489 /* DEBUG: dump the SN regs */
490 SonixCamDevice::DumpRegs()
491 {
492 	uint8 regs[SN9C102_REG_COUNT];
493 	status_t err;
494 
495 	//err = sonix_get_regs(dev, SN_ASIC_ID, regs, SN_REG_COUNT);
496 	err = ReadReg(0, regs, SN9C102_REG_COUNT);
497 	if (err < 0)
498 		return;
499 	printf("REG1: %02x %02x %02x %02x  %02x %02x %02x %02x\n",
500 			regs[0], regs[1], regs[2], regs[3], regs[4], regs[5], regs[6], regs[7]);
501 	printf("   2: %02x %02x %02x %02x  %02x %02x %02x %02x\n",
502 			regs[8], regs[9], regs[10], regs[11], regs[12], regs[13], regs[14], regs[15]);
503 	printf("   3: %02x %02x %02x %02x  %02x %02x %02x %02x\n",
504 			regs[16], regs[17], regs[18], regs[19], regs[20], regs[21], regs[22], regs[23]);
505 	printf("   4: %02x %02x %02x %02x  %02x %02x %02x %02x\n",
506 			regs[24], regs[25], regs[26], regs[27], regs[28], regs[29], regs[30], regs[31]);
507 }
508 
509 // -----------------------------------------------------------------------------
510 status_t
511 SonixCamDevice::SendCommand(uint8 dir, uint8 request, uint16 value,
512 							uint16 index, uint16 length, void* data)
513 {
514 	size_t ret;
515 	if (length > 64)
516 		return EINVAL;
517 	if (!GetDevice())
518 		return ENODEV;
519 	ret = GetDevice()->ControlTransfer(
520 				USB_REQTYPE_VENDOR | USB_REQTYPE_INTERFACE_OUT | dir,
521 				request, value, index, length, data);
522 	return ret;
523 }
524 
525 // -----------------------------------------------------------------------------
526 SonixCamDeviceAddon::SonixCamDeviceAddon(WebCamMediaAddOn* webcam)
527 	: CamDeviceAddon(webcam)
528 {
529 	SetSupportedDevices(kSupportedDevices);
530 }
531 
532 // -----------------------------------------------------------------------------
533 SonixCamDeviceAddon::~SonixCamDeviceAddon()
534 {
535 }
536 
537 // -----------------------------------------------------------------------------
538 const char *
539 SonixCamDeviceAddon::BrandName()
540 {
541 	return "Sonix";
542 }
543 
544 // -----------------------------------------------------------------------------
545 SonixCamDevice *
546 SonixCamDeviceAddon::Instantiate(CamRoster &roster, BUSBDevice *from)
547 {
548 	return new SonixCamDevice(*this, from);
549 }
550 
551 extern "C" status_t
552 B_WEBCAM_MKINTFUNC(sonix)
553 (WebCamMediaAddOn* webcam, CamDeviceAddon **addon)
554 {
555 	*addon = new SonixCamDeviceAddon(webcam);
556 	return B_OK;
557 }
558 
559 // XXX: REMOVE ME
560 
561 
562 
563 /*
564  * BAYER2RGB24 ROUTINE TAKEN FROM:
565  *
566  * Sonix SN9C101 based webcam basic I/F routines
567  * Copyright (C) 2004 Takafumi Mizuno <taka-qce@ls-a.jp>
568  *
569  * Redistribution and use in source and binary forms, with or without
570  * modification, are permitted provided that the following conditions
571  * are met:
572  * 1. Redistributions of source code must retain the above copyright
573  *    notice, this list of conditions and the following disclaimer.
574  * 2. Redistributions in binary form must reproduce the above copyright
575  *    notice, this list of conditions and the following disclaimer in the
576  *    documentation and/or other materials provided with the distribution.
577  *
578  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
579  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
580  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
581  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
582  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
583  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
584  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
585  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
586  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
587  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
588  * SUCH DAMAGE.
589  */
590 
591 void bayer2rgb24(unsigned char *dst, unsigned char *src, long int WIDTH, long int HEIGHT)
592 {
593     long int i;
594     unsigned char *rawpt, *scanpt;
595     long int size;
596 
597     rawpt = src;
598     scanpt = dst;
599     size = WIDTH*HEIGHT;
600 
601     for ( i = 0; i < size; i++ ) {
602 	if ( (i/WIDTH) % 2 == 0 ) {
603 	    if ( (i % 2) == 0 ) {
604 		/* B */
605 		if ( (i > WIDTH) && ((i % WIDTH) > 0) ) {
606 		    *scanpt++ = (*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+
607 				 *(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4;	/* R */
608 		    *scanpt++ = (*(rawpt-1)+*(rawpt+1)+
609 				 *(rawpt+WIDTH)+*(rawpt-WIDTH))/4;	/* G */
610 		    *scanpt++ = *rawpt;					/* B */
611 		} else {
612 		    /* first line or left column */
613 		    *scanpt++ = *(rawpt+WIDTH+1);		/* R */
614 		    *scanpt++ = (*(rawpt+1)+*(rawpt+WIDTH))/2;	/* G */
615 		    *scanpt++ = *rawpt;				/* B */
616 		}
617 	    } else {
618 		/* (B)G */
619 		if ( (i > WIDTH) && ((i % WIDTH) < (WIDTH-1)) ) {
620 		    *scanpt++ = (*(rawpt+WIDTH)+*(rawpt-WIDTH))/2;	/* R */
621 		    *scanpt++ = *rawpt;					/* G */
622 		    *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2;		/* B */
623 		} else {
624 		    /* first line or right column */
625 		    *scanpt++ = *(rawpt+WIDTH);	/* R */
626 		    *scanpt++ = *rawpt;		/* G */
627 		    *scanpt++ = *(rawpt-1);	/* B */
628 		}
629 	    }
630 	} else {
631 	    if ( (i % 2) == 0 ) {
632 		/* G(R) */
633 		if ( (i < (WIDTH*(HEIGHT-1))) && ((i % WIDTH) > 0) ) {
634 		    *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2;		/* R */
635 		    *scanpt++ = *rawpt;					/* G */
636 		    *scanpt++ = (*(rawpt+WIDTH)+*(rawpt-WIDTH))/2;	/* B */
637 		} else {
638 		    /* bottom line or left column */
639 		    *scanpt++ = *(rawpt+1);		/* R */
640 		    *scanpt++ = *rawpt;			/* G */
641 		    *scanpt++ = *(rawpt-WIDTH);		/* B */
642 		}
643 	    } else {
644 		/* R */
645 		if ( i < (WIDTH*(HEIGHT-1)) && ((i % WIDTH) < (WIDTH-1)) ) {
646 		    *scanpt++ = *rawpt;					/* R */
647 		    *scanpt++ = (*(rawpt-1)+*(rawpt+1)+
648 				 *(rawpt-WIDTH)+*(rawpt+WIDTH))/4;	/* G */
649 		    *scanpt++ = (*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+
650 				 *(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4;	/* B */
651 		} else {
652 		    /* bottom line or right column */
653 		    *scanpt++ = *rawpt;				/* R */
654 		    *scanpt++ = (*(rawpt-1)+*(rawpt-WIDTH))/2;	/* G */
655 		    *scanpt++ = *(rawpt-WIDTH-1);		/* B */
656 		}
657 	    }
658 	}
659 	rawpt++;
660     }
661 
662 }
663 
664 /* modified bayer2rgb24 to output rgb-32 little endian (B_RGB32)
665  * François Revol
666  */
667 
668 void bayer2rgb32le(unsigned char *dst, unsigned char *src, long int WIDTH, long int HEIGHT)
669 {
670     long int i;
671     unsigned char *rawpt, *scanpt;
672     long int size;
673 
674     rawpt = src;
675     scanpt = dst;
676     size = WIDTH*HEIGHT;
677 
678     for ( i = 0; i < size; i++ ) {
679 	if ( (i/WIDTH) % 2 == 0 ) {
680 	    if ( (i % 2) == 0 ) {
681 		/* B */
682 		if ( (i > WIDTH) && ((i % WIDTH) > 0) ) {
683 		    *scanpt++ = *rawpt;					/* B */
684 		    *scanpt++ = (*(rawpt-1)+*(rawpt+1)+
685 				 *(rawpt+WIDTH)+*(rawpt-WIDTH))/4;	/* G */
686 		    *scanpt++ = (*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+
687 				 *(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4;	/* R */
688 		} else {
689 		    /* first line or left column */
690 		    *scanpt++ = *rawpt;				/* B */
691 		    *scanpt++ = (*(rawpt+1)+*(rawpt+WIDTH))/2;	/* G */
692 		    *scanpt++ = *(rawpt+WIDTH+1);		/* R */
693 		}
694 	    } else {
695 		/* (B)G */
696 		if ( (i > WIDTH) && ((i % WIDTH) < (WIDTH-1)) ) {
697 		    *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2;		/* B */
698 		    *scanpt++ = *rawpt;					/* G */
699 		    *scanpt++ = (*(rawpt+WIDTH)+*(rawpt-WIDTH))/2;	/* R */
700 		} else {
701 		    /* first line or right column */
702 		    *scanpt++ = *(rawpt-1);	/* B */
703 		    *scanpt++ = *rawpt;		/* G */
704 		    *scanpt++ = *(rawpt+WIDTH);	/* R */
705 		}
706 	    }
707 	} else {
708 	    if ( (i % 2) == 0 ) {
709 		/* G(R) */
710 		if ( (i < (WIDTH*(HEIGHT-1))) && ((i % WIDTH) > 0) ) {
711 		    *scanpt++ = (*(rawpt+WIDTH)+*(rawpt-WIDTH))/2;	/* B */
712 		    *scanpt++ = *rawpt;					/* G */
713 		    *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2;		/* R */
714 		} else {
715 		    /* bottom line or left column */
716 		    *scanpt++ = *(rawpt-WIDTH);		/* B */
717 		    *scanpt++ = *rawpt;			/* G */
718 		    *scanpt++ = *(rawpt+1);		/* R */
719 		}
720 	    } else {
721 		/* R */
722 		if ( i < (WIDTH*(HEIGHT-1)) && ((i % WIDTH) < (WIDTH-1)) ) {
723 		    *scanpt++ = (*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+
724 				 *(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4;	/* B */
725 		    *scanpt++ = (*(rawpt-1)+*(rawpt+1)+
726 				 *(rawpt-WIDTH)+*(rawpt+WIDTH))/4;	/* G */
727 		    *scanpt++ = *rawpt;					/* R */
728 		} else {
729 		    /* bottom line or right column */
730 		    *scanpt++ = *(rawpt-WIDTH-1);		/* B */
731 		    *scanpt++ = (*(rawpt-1)+*(rawpt-WIDTH))/2;	/* G */
732 		    *scanpt++ = *rawpt;				/* R */
733 		}
734 	    }
735 	}
736 	rawpt++;
737 	scanpt++;
738     }
739 
740 }
741 
742 
743