xref: /haiku/src/add-ons/media/media-add-ons/usb_webcam/addons/sonix/SonixCamDevice.cpp (revision edb484677944d3243760cea487fc8c9dbbd032eb)
1a1830cbdSFrançois Revol /*
2a1830cbdSFrançois Revol  * Copyright 2004-2008, François Revol, <revol@free.fr>.
3a1830cbdSFrançois Revol  * Distributed under the terms of the MIT License.
4a1830cbdSFrançois Revol  */
5a1830cbdSFrançois Revol 
62c9bd703SFrançois Revol #include "SonixCamDevice.h"
72c9bd703SFrançois Revol #include "CamDebug.h"
82c9bd703SFrançois Revol #include "CamSensor.h"
92c9bd703SFrançois Revol #include "CamBufferingDeframer.h"
102c9bd703SFrançois Revol #include "CamStreamingDeframer.h"
112c9bd703SFrançois Revol 
12a486abdcSFrançois Revol #include <ParameterWeb.h>
132c9bd703SFrançois Revol #include <interface/Bitmap.h>
142c9bd703SFrançois Revol #include <media/Buffer.h>
152c9bd703SFrançois Revol 
1674b3713aSFrançois Revol const usb_webcam_support_descriptor kSupportedDevices[] = {
17d55e0f83SFrançois Revol {{ 0, 0, 0, 0x0c45, 0x6005 }, "Sonix", "Sonix", "tas5110c1b" }, // mine
18fb086488SFrançois Revol {{ 0, 0, 0, 0x0c45, 0x6007 }, "Sonix", "macally ICECAM", "tas5110c1b" }, // Rajah's cam - SN9C101R
1974b3713aSFrançois Revol {{ 0, 0, 0, 0x0c45, 0x6009 }, "Trust", "spacec@m 120", NULL },
2074b3713aSFrançois Revol {{ 0, 0, 0, 0x0c45, 0x600d }, "Trust", "spacec@m 120", NULL },
211571aa7fSFrançois Revol 
221571aa7fSFrançois Revol /* other devices that should be supported,
231571aa7fSFrançois Revol  * cf. sn9c102-1.15 linux driver, sn9c102_sensor.h
241571aa7fSFrançois Revol  * for IDs and sensors
251571aa7fSFrançois Revol  */
2674b3713aSFrançois Revol {{ 0, 0, 0, 0x0c45, 0x6001 }, "Sonix", "Sonix generic", "tas5110c1b" },
2774b3713aSFrançois Revol {{ 0, 0, 0, 0x0c45, 0x6024 }, "Sonix", "Sonix generic", NULL },
2874b3713aSFrançois Revol {{ 0, 0, 0, 0x0c45, 0x6025 }, "Sonix", "Sonix generic", "tas5110c1b,XXX" },
2974b3713aSFrançois Revol {{ 0, 0, 0, 0x0c45, 0x6028 }, "Sonix", "Sonix generic", NULL },
3074b3713aSFrançois Revol {{ 0, 0, 0, 0x0c45, 0x6029 }, "Sonix", "Sonix generic", NULL },
3174b3713aSFrançois Revol {{ 0, 0, 0, 0x0c45, 0x602a }, "Sonix", "Sonix generic", NULL },
3274b3713aSFrançois Revol {{ 0, 0, 0, 0x0c45, 0x602b }, "Sonix", "Sonix generic", NULL },
3374b3713aSFrançois Revol {{ 0, 0, 0, 0x0c45, 0x602c }, "Sonix", "Sonix generic", NULL },
3474b3713aSFrançois Revol {{ 0, 0, 0, 0x0c45, 0x6030 }, "Sonix", "Sonix generic", NULL },
3574b3713aSFrançois Revol {{ 0, 0, 0, 0x0c45, 0x6080 }, "Sonix", "Sonix generic", NULL },
3674b3713aSFrançois Revol {{ 0, 0, 0, 0x0c45, 0x6082 }, "Sonix", "Sonix generic", NULL },
3774b3713aSFrançois Revol {{ 0, 0, 0, 0x0c45, 0x6083 }, "Sonix", "Sonix generic", NULL },
3874b3713aSFrançois Revol {{ 0, 0, 0, 0x0c45, 0x6088 }, "Sonix", "Sonix generic", NULL },
3974b3713aSFrançois Revol {{ 0, 0, 0, 0x0c45, 0x608a }, "Sonix", "Sonix generic", NULL },
4074b3713aSFrançois Revol {{ 0, 0, 0, 0x0c45, 0x608b }, "Sonix", "Sonix generic", NULL },
4174b3713aSFrançois Revol {{ 0, 0, 0, 0x0c45, 0x608c }, "Sonix", "Sonix generic", NULL },
4274b3713aSFrançois Revol {{ 0, 0, 0, 0x0c45, 0x608e }, "Sonix", "Sonix generic", NULL },
4374b3713aSFrançois Revol {{ 0, 0, 0, 0x0c45, 0x608f }, "Sonix", "Sonix generic", NULL },
4474b3713aSFrançois Revol {{ 0, 0, 0, 0x0c45, 0x60a0 }, "Sonix", "Sonix generic", NULL },
4574b3713aSFrançois Revol {{ 0, 0, 0, 0x0c45, 0x60a2 }, "Sonix", "Sonix generic", NULL },
4674b3713aSFrançois Revol {{ 0, 0, 0, 0x0c45, 0x60a3 }, "Sonix", "Sonix generic", NULL },
4774b3713aSFrançois Revol {{ 0, 0, 0, 0x0c45, 0x60a8 }, "Sonix", "Sonix generic", NULL },
4874b3713aSFrançois Revol {{ 0, 0, 0, 0x0c45, 0x60aa }, "Sonix", "Sonix generic", NULL },
4974b3713aSFrançois Revol {{ 0, 0, 0, 0x0c45, 0x60ab }, "Sonix", "Sonix generic", "tas5110c1b" },
5074b3713aSFrançois Revol {{ 0, 0, 0, 0x0c45, 0x60ac }, "Sonix", "Sonix generic", NULL },
5174b3713aSFrançois Revol {{ 0, 0, 0, 0x0c45, 0x60ae }, "Sonix", "Sonix generic", NULL },
5274b3713aSFrançois Revol {{ 0, 0, 0, 0x0c45, 0x60af }, "Sonix", "Sonix generic", NULL },
5374b3713aSFrançois Revol {{ 0, 0, 0, 0x0c45, 0x60b0 }, "Sonix", "Sonix generic", NULL },
5474b3713aSFrançois Revol {{ 0, 0, 0, 0x0c45, 0x60b2 }, "Sonix", "Sonix generic", NULL },
5574b3713aSFrançois Revol {{ 0, 0, 0, 0x0c45, 0x60b3 }, "Sonix", "Sonix generic", NULL },
5674b3713aSFrançois Revol {{ 0, 0, 0, 0x0c45, 0x60b8 }, "Sonix", "Sonix generic", NULL },
5774b3713aSFrançois Revol {{ 0, 0, 0, 0x0c45, 0x60ba }, "Sonix", "Sonix generic", NULL },
5874b3713aSFrançois Revol {{ 0, 0, 0, 0x0c45, 0x60bb }, "Sonix", "Sonix generic", NULL },
5974b3713aSFrançois Revol {{ 0, 0, 0, 0x0c45, 0x60bc }, "Sonix", "Sonix generic", NULL },
6074b3713aSFrançois Revol {{ 0, 0, 0, 0x0c45, 0x60be }, "Sonix", "Sonix generic", NULL },
6174b3713aSFrançois Revol {{ 0, 0, 0, 0, 0}, NULL, NULL, NULL }
622c9bd703SFrançois Revol };
632c9bd703SFrançois Revol 
642c9bd703SFrançois Revol // 12 bytes actually
652c9bd703SFrançois Revol static const uint8 sof_mark_1[] = { 0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x00 };
662c9bd703SFrançois Revol static const uint8 sof_mark_2[] = { 0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x01 };
672c9bd703SFrançois Revol static const uint8 *sof_marks[] = { sof_mark_1, sof_mark_2 };
682c9bd703SFrançois Revol 
692c9bd703SFrançois Revol static const uint8 eof_mark_1[] = { 0x00, 0x00, 0x00, 0x00 };
702c9bd703SFrançois Revol static const uint8 eof_mark_2[] = { 0x40, 0x00, 0x00, 0x00 };
712c9bd703SFrançois Revol static const uint8 eof_mark_3[] = { 0x80, 0x00, 0x00, 0x00 };
722c9bd703SFrançois Revol static const uint8 eof_mark_4[] = { 0xc0, 0x00, 0x00, 0x00 };
732c9bd703SFrançois Revol static const uint8 *eof_marks[] = { eof_mark_1, eof_mark_2, eof_mark_3, eof_mark_4 };
742c9bd703SFrançois Revol 
752c9bd703SFrançois Revol void bayer2rgb24(unsigned char *dst, unsigned char *src, long int WIDTH, long int HEIGHT);
762c9bd703SFrançois Revol void bayer2rgb32le(unsigned char *dst, unsigned char *src, long int WIDTH, long int HEIGHT);
772c9bd703SFrançois Revol 
7874b3713aSFrançois Revol 
SonixCamDevice(CamDeviceAddon & _addon,BUSBDevice * _device)792c9bd703SFrançois Revol SonixCamDevice::SonixCamDevice(CamDeviceAddon &_addon, BUSBDevice* _device)
802c9bd703SFrançois Revol           :CamDevice(_addon, _device)
812c9bd703SFrançois Revol {
822c9bd703SFrançois Revol 	uchar data[8]; /* store bytes returned from sonix commands */
832c9bd703SFrançois Revol 	status_t err;
842c9bd703SFrançois Revol 	fFrameTagState = 0;
852c9bd703SFrançois Revol 
86a486abdcSFrançois Revol 	fRGain = fGGain = fBGain = 0;
87c38af24cSFrançois Revol 	// unknown
88c38af24cSFrançois Revol 	fBrightness = 0.5;
89a486abdcSFrançois Revol 
902c9bd703SFrançois Revol 	memset(fCachedRegs, 0, SN9C102_REG_COUNT);
912c9bd703SFrançois Revol 	fChipVersion = 2;
922c9bd703SFrançois Revol 	if ((GetDevice()->ProductID() & ~0x3F) == 0x6080) {
932c9bd703SFrançois Revol 		fChipVersion = 3; // says V4L2
942c9bd703SFrançois Revol 	}
9574b3713aSFrançois Revol 	err = ProbeSensor();
962c9bd703SFrançois Revol 
972c9bd703SFrançois Revol //	fDeframer = new CamBufferingDeframer(this);
982c9bd703SFrançois Revol 	fDeframer = new CamStreamingDeframer(this);
992c9bd703SFrançois Revol 	fDeframer->RegisterSOFTags(sof_marks, 2, sizeof(sof_mark_1), 12);
1002c9bd703SFrançois Revol 	fDeframer->RegisterEOFTags(eof_marks, 4, sizeof(eof_mark_1), sizeof(eof_mark_1));
1012c9bd703SFrançois Revol 	SetDataInput(fDeframer);
1022c9bd703SFrançois Revol 
1032c9bd703SFrançois Revol 	/* init hw */
1042c9bd703SFrançois Revol 
1052c9bd703SFrançois Revol 	const BUSBConfiguration *config = GetDevice()->ConfigurationAt(0);
1062c9bd703SFrançois Revol 	if (config) {
1072c9bd703SFrançois Revol 		const BUSBInterface *inter = config->InterfaceAt(0);
108e53032e5SFrançois Revol 		uint32 i;
1092c9bd703SFrançois Revol 
1102c9bd703SFrançois Revol 		GetDevice()->SetConfiguration(config);
1112c9bd703SFrançois Revol 
1122c9bd703SFrançois Revol 		for (i = 0; inter && (i < inter->CountEndpoints()); i++) {
1132c9bd703SFrançois Revol 			const BUSBEndpoint *e = inter->EndpointAt(i);
1142c9bd703SFrançois Revol 			if (e && e->IsBulk() && e->IsInput()) {
1152c9bd703SFrançois Revol 				fBulkIn = e;
1162c9bd703SFrançois Revol 				PRINT((CH ": Using inter[0].endpoint[%d]; maxpktsz: %d" CT, i, e->MaxPacketSize()));
1172c9bd703SFrançois Revol 				break;
1182c9bd703SFrançois Revol 			}
1192c9bd703SFrançois Revol 		}
1202c9bd703SFrançois Revol 
1212c9bd703SFrançois Revol 	}
1222c9bd703SFrançois Revol 
1232c9bd703SFrançois Revol 	/* sanity check */
1242c9bd703SFrançois Revol 	err = ReadReg(SN9C102_ASIC_ID, data);
1252c9bd703SFrançois Revol 	if (err < 0 || data[0] != 0x10) {
1262c9bd703SFrançois Revol 		PRINT((CH ": BAD ASIC signature! (%u != %u)" CT, data[0], 0x10));
1272c9bd703SFrançois Revol 		return;
1282c9bd703SFrançois Revol 	}
1292c9bd703SFrançois Revol 
130fb086488SFrançois Revol 		//XXX: the XP driver sends this to the ICECAM... need to investigate.
131fb086488SFrançois Revol #if 1
132fb086488SFrançois Revol 	uint8 tmp_3[] = {
133fb086488SFrançois Revol 		0x44, 0x44, 0x00, 0x00, 0x00, 0x04, 0x00, 0xa0,
134fb086488SFrançois Revol 		0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
135fb086488SFrançois Revol 		0x00, 0x41, 0x09, 0x00, 0x16, 0x12, 0x60, 0x86,
136fb086488SFrançois Revol 		0x3b, 0x0f, 0x0e, 0x06, 0x00, 0x00, 0x03 };
137fb086488SFrançois Revol 	WriteReg(SN9C102_CHIP_CTRL, tmp_3, 0x1f);
138fb086488SFrançois Revol #endif
139fb086488SFrançois Revol 		//XXX:DEBUG
140fb086488SFrançois Revol 
141fb086488SFrançois Revol #if 0
142fb086488SFrançois Revol 		//XXX: the XP driver sends all this... investigate.
143fb086488SFrançois Revol 	uint8 tmp_1[] = {0x09, 0x44};
144fb086488SFrançois Revol 	WriteReg(SN9C102_CHIP_CTRL, tmp_1, sizeof(tmp_1));
145fb086488SFrançois Revol 	WriteReg8(SN9C102_CHIP_CTRL, 0x44);
146fb086488SFrançois Revol 
147fb086488SFrançois Revol 	WriteReg8(SN9C102_CLOCK_SEL /*0x17*/, 0x29);
148fb086488SFrançois Revol 
149fb086488SFrançois Revol 	uint8 tmp_2[] = {0x44, 0x44};
150fb086488SFrançois Revol 	WriteReg(SN9C102_CHIP_CTRL, tmp_2, 2);
151fb086488SFrançois Revol 		//URB_FUNCTION_VENDOR_INTERFACE:
152fb086488SFrançois Revol 		//(USBD_TRANSFER_DIRECTION_OUT, ~USBD_SHORT_TRANSFER_OK)
153fb086488SFrançois Revol 
154fb086488SFrançois Revol 	uint8 tmp_3[] = {
155fb086488SFrançois Revol 		0x44, 0x44, 0x00, 0x00, 0x00, 0x04, 0x00, 0xa0,
156fb086488SFrançois Revol 		0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
157fb086488SFrançois Revol 		0x00, 0x41, 0x09, 0x00, 0x16, 0x12, 0x60, 0x86,
158fb086488SFrançois Revol 		0x3b, 0x0f, 0x0e, 0x06, 0x00, 0x00, 0x03 };
159fb086488SFrançois Revol 	WriteReg(SN9C102_CHIP_CTRL, tmp_3, 0x1f);
160fb086488SFrançois Revol 
161fb086488SFrançois Revol 	uint8 tmp_4[] = {0x01, 0x01, 0x07, 0x06};
162fb086488SFrançois Revol 	//WriteReg(SN9C102_AE_STRX, tmp_4, 4);
163fb086488SFrançois Revol 
164fb086488SFrançois Revol 	uint8 tmp_5[] = {0x14, 0x0f};
165fb086488SFrançois Revol 	//WriteReg(SN9C102_H_SIZE, tmp_5, 2);
166fb086488SFrançois Revol 
167fb086488SFrançois Revol 	WriteReg8(SN9C102_SYNC_N_SCALE, 0x86);
168fb086488SFrançois Revol 
169fb086488SFrançois Revol 	WriteReg8(SN9C102_CHIP_CTRL, 0x44);	// again ??
170fb086488SFrançois Revol 
171fb086488SFrançois Revol 	uint8 tmp_6[] = { 0x60, 0x86 };
172fb086488SFrançois Revol 	WriteReg(SN9C102_CLOCK_SEL /*0x17*/, tmp_6, 2);
173fb086488SFrançois Revol 
174fb086488SFrançois Revol 	WriteReg8(SN9C102_PIX_CLK, 0x2b);
175fb086488SFrançois Revol 
176fb086488SFrançois Revol 	// some IIC stuff for the sensor
177fb086488SFrançois Revol 	uint8 tmp_7[] = { 0xb0, 0x61, 0x1c, 0xf8, 0x10, 0x00, 0x00, 0x16 };
178fb086488SFrançois Revol 	//WriteReg(SN9C102_I2C_SETUP, tmp_7, 8);
179fb086488SFrançois Revol 
180fb086488SFrançois Revol 	WriteReg8(SN9C102_PIX_CLK, 0x4b);
181fb086488SFrançois Revol 
182fb086488SFrançois Revol 	uint8 tmp_8[] = { 0xa0, 0x61, 0x1c, 0x0f, 0x10, 0x00, 0x00, 0x16 };
183fb086488SFrançois Revol 	//WriteReg(SN9C102_I2C_SETUP, tmp_8, 8);
184fb086488SFrançois Revol 
185fb086488SFrançois Revol #endif
186fb086488SFrançois Revol #if 0
187fb086488SFrançois Revol 	// some IIC stuff for the sensor
188fb086488SFrançois Revol 	uint8 tmp_7[] = { 0xb0, 0x61, 0x1c, 0xf8, 0x10, 0x00, 0x00, 0x16 };
189fb086488SFrançois Revol 	WriteReg(SN9C102_I2C_SETUP, tmp_7, 8);
190fb086488SFrançois Revol 
191fb086488SFrançois Revol 	WriteReg8(SN9C102_PIX_CLK, 0x4b);
192fb086488SFrançois Revol 
193fb086488SFrançois Revol 	uint8 tmp_8[] = { 0xa0, 0x61, 0x1c, 0x0f, 0x10, 0x00, 0x00, 0x16};
194fb086488SFrançois Revol 	WriteReg(SN9C102_I2C_SETUP, tmp_8, 8);
195fb086488SFrançois Revol #endif
196fb086488SFrançois Revol 
197fb086488SFrançois Revol 	//WriteReg8(SN9C102_PIX_CLK, 0x4b);
198fb086488SFrançois Revol 
199fb086488SFrançois Revol //###############
2002c9bd703SFrançois Revol 
2012c9bd703SFrançois Revol 	if (Sensor()) {
2022c9bd703SFrançois Revol 		PRINT((CH ": CamSensor: %s" CT, Sensor()->Name()));
2032c9bd703SFrançois Revol 		fInitStatus = Sensor()->Setup();
204fb086488SFrançois Revol 
205a486abdcSFrançois Revol 		fVideoFrame = BRect(0, 0, Sensor()->MaxWidth()-1, Sensor()->MaxHeight()-1);
2062c9bd703SFrançois Revol //		SetVideoFrame(BRect(0, 0, Sensor()->MaxWidth()-1, Sensor()->MaxHeight()-1));
2072c9bd703SFrançois Revol //		SetVideoFrame(BRect(0, 0, 320-1, 240-1));
2082c9bd703SFrançois Revol 	}
2092c9bd703SFrançois Revol 	//SetScale(1);
2102c9bd703SFrançois Revol }
2112c9bd703SFrançois Revol 
21274b3713aSFrançois Revol 
~SonixCamDevice()2132c9bd703SFrançois Revol SonixCamDevice::~SonixCamDevice()
2142c9bd703SFrançois Revol {
2152c9bd703SFrançois Revol 	if (Sensor())
2162c9bd703SFrançois Revol 		delete fSensor;
2172c9bd703SFrançois Revol 	fSensor = NULL;
2182c9bd703SFrançois Revol }
2192c9bd703SFrançois Revol 
22074b3713aSFrançois Revol 
2212c9bd703SFrançois Revol bool
SupportsBulk()2222c9bd703SFrançois Revol SonixCamDevice::SupportsBulk()
2232c9bd703SFrançois Revol {
2242c9bd703SFrançois Revol 	return true;
2252c9bd703SFrançois Revol }
2262c9bd703SFrançois Revol 
22774b3713aSFrançois Revol 
2282c9bd703SFrançois Revol bool
SupportsIsochronous()2292c9bd703SFrançois Revol SonixCamDevice::SupportsIsochronous()
2302c9bd703SFrançois Revol {
2312c9bd703SFrançois Revol 	return true;
2322c9bd703SFrançois Revol }
2332c9bd703SFrançois Revol 
23474b3713aSFrançois Revol 
2352c9bd703SFrançois Revol status_t
StartTransfer()2362c9bd703SFrançois Revol SonixCamDevice::StartTransfer()
2372c9bd703SFrançois Revol {
2382c9bd703SFrançois Revol 	status_t err;
2392c9bd703SFrançois Revol 	uint8 r;
2402c9bd703SFrançois Revol 
2412c9bd703SFrançois Revol 	SetScale(1);
2422c9bd703SFrançois Revol 	if (Sensor())
2430866ac7eSFrançois Revol 		SetVideoFrame(fVideoFrame);
2442c9bd703SFrançois Revol 
245a486abdcSFrançois Revol 	//SetVideoFrame(BRect(0, 0, 320-1, 240-1));
2462c9bd703SFrançois Revol 
2472c9bd703SFrançois Revol DumpRegs();
2482c9bd703SFrançois Revol 	err = ReadReg(SN9C102_CHIP_CTRL, &r, 1, true);
2492c9bd703SFrançois Revol 	if (err < 0)
2502c9bd703SFrançois Revol 		return err;
2512c9bd703SFrançois Revol 	r |= 0x04;
2522c9bd703SFrançois Revol 	err = WriteReg8(SN9C102_CHIP_CTRL, r);
2532c9bd703SFrançois Revol 	if (err < 0)
2542c9bd703SFrançois Revol 		return err;
2552c9bd703SFrançois Revol 	return CamDevice::StartTransfer();
2562c9bd703SFrançois Revol }
2572c9bd703SFrançois Revol 
25874b3713aSFrançois Revol 
2592c9bd703SFrançois Revol status_t
StopTransfer()2602c9bd703SFrançois Revol SonixCamDevice::StopTransfer()
2612c9bd703SFrançois Revol {
2622c9bd703SFrançois Revol 	status_t err;
2632c9bd703SFrançois Revol 	uint8 r;
2642c9bd703SFrançois Revol 
2652c9bd703SFrançois Revol DumpRegs();
2662c9bd703SFrançois Revol 	err = CamDevice::StopTransfer();
2672c9bd703SFrançois Revol //	if (err < 0)
2682c9bd703SFrançois Revol //		return err;
2692c9bd703SFrançois Revol 	err = ReadReg(SN9C102_CHIP_CTRL, &r, 1, true);
2702c9bd703SFrançois Revol 	if (err < 0)
2712c9bd703SFrançois Revol 		return err;
2722c9bd703SFrançois Revol 	r &= ~0x04;
2732c9bd703SFrançois Revol 	err = WriteReg8(SN9C102_CHIP_CTRL, r);
2742c9bd703SFrançois Revol 	if (err < 0)
2752c9bd703SFrançois Revol 		return err;
2762c9bd703SFrançois Revol 	return err;
2772c9bd703SFrançois Revol }
2782c9bd703SFrançois Revol 
27974b3713aSFrançois Revol 
280fb086488SFrançois Revol status_t
PowerOnSensor(bool on)281fb086488SFrançois Revol SonixCamDevice::PowerOnSensor(bool on)
282fb086488SFrançois Revol {
283fb086488SFrançois Revol 	if (OrReg8(SN9C102_CHIP_CTRL, on ? 0x01 : 0x00) < 0)
284fb086488SFrançois Revol 		return EIO;
285fb086488SFrançois Revol 	return B_OK;
286fb086488SFrançois Revol }
287fb086488SFrançois Revol 
288fb086488SFrançois Revol 
2892c9bd703SFrançois Revol ssize_t
WriteReg(uint16 address,uint8 * data,size_t count)2902c9bd703SFrançois Revol SonixCamDevice::WriteReg(uint16 address, uint8 *data, size_t count)
2912c9bd703SFrançois Revol {
292*edb48467SMurai Takashi 	PRINT((CH "(%u, @%p, %" B_PRIuSIZE ")" CT, address, data, count));
293fb086488SFrançois Revol 	status_t err;
2942c9bd703SFrançois Revol 	if (address + count > SN9C102_REG_COUNT) {
295*edb48467SMurai Takashi 		PRINT((CH ": Invalid register range [%u;%" B_PRIuSIZE "]" CT, address,
296*edb48467SMurai Takashi 			address + count));
2972c9bd703SFrançois Revol 		return EINVAL;
2982c9bd703SFrançois Revol 	}
2992c9bd703SFrançois Revol 	memcpy(&fCachedRegs[address], data, count);
300fb086488SFrançois Revol 	err = SendCommand(USB_REQTYPE_DEVICE_OUT, 0x08, address, 0, count, data);
301fb086488SFrançois Revol 	if (err < B_OK)
302fb086488SFrançois Revol 		return err;
303fb086488SFrançois Revol 	return count;
3042c9bd703SFrançois Revol }
3052c9bd703SFrançois Revol 
30674b3713aSFrançois Revol 
3072c9bd703SFrançois Revol ssize_t
ReadReg(uint16 address,uint8 * data,size_t count,bool cached)3082c9bd703SFrançois Revol SonixCamDevice::ReadReg(uint16 address, uint8 *data, size_t count, bool cached)
3092c9bd703SFrançois Revol {
310*edb48467SMurai Takashi 	PRINT((CH "(%u, @%p, %" B_PRIuSIZE ", %d)" CT, address, data, count,
311*edb48467SMurai Takashi 		cached));
312fb086488SFrançois Revol 	status_t err;
3132c9bd703SFrançois Revol 	if (address + count > SN9C102_REG_COUNT) {
314*edb48467SMurai Takashi 		PRINT((CH ": Invalid register range [%u;%" B_PRIuSIZE "]" CT, address,
315*edb48467SMurai Takashi 			address + count));
3162c9bd703SFrançois Revol 		return EINVAL;
3172c9bd703SFrançois Revol 	}
3182c9bd703SFrançois Revol 	if (cached) {
3192c9bd703SFrançois Revol 		memcpy(data, &fCachedRegs[address], count);
3202c9bd703SFrançois Revol 		return count;
3212c9bd703SFrançois Revol 	}
322fb086488SFrançois Revol 	err = SendCommand(USB_REQTYPE_DEVICE_IN, 0x00, address, 0, count, data);
323fb086488SFrançois Revol 	if (err < B_OK)
324fb086488SFrançois Revol 		return err;
325fb086488SFrançois Revol 	return count;
3262c9bd703SFrançois Revol }
3272c9bd703SFrançois Revol 
32874b3713aSFrançois Revol 
3292c9bd703SFrançois Revol status_t
GetStatusIIC()3302c9bd703SFrançois Revol SonixCamDevice::GetStatusIIC()
3312c9bd703SFrançois Revol {
3322c9bd703SFrançois Revol 	status_t err;
3332c9bd703SFrançois Revol 	uint8 status = 0;
3342c9bd703SFrançois Revol 	err = ReadReg(SN9C102_I2C_SETUP, &status);
3352c9bd703SFrançois Revol 	//dprintf(ID "i2c_status: error 0x%08lx, status = %02x\n", err, status);
3362c9bd703SFrançois Revol 	if (err < 0)
3372c9bd703SFrançois Revol 		return err;
3382c9bd703SFrançois Revol 	return (status&0x08)?EIO:0;
3392c9bd703SFrançois Revol }
3402c9bd703SFrançois Revol 
34174b3713aSFrançois Revol 
3422c9bd703SFrançois Revol status_t
WaitReadyIIC()3432c9bd703SFrançois Revol SonixCamDevice::WaitReadyIIC()
3442c9bd703SFrançois Revol {
3452c9bd703SFrançois Revol 	status_t err;
3462c9bd703SFrançois Revol 	uint8 status = 0;
3472c9bd703SFrançois Revol 	int tries = 5;
3482c9bd703SFrançois Revol 	if (!Sensor())
3492c9bd703SFrançois Revol 		return B_NO_INIT;
3502c9bd703SFrançois Revol 	while (tries--) {
3512c9bd703SFrançois Revol 		err = ReadReg(SN9C102_I2C_SETUP, &status);
3522c9bd703SFrançois Revol 		//dprintf(ID "i2c_wait_ready: error 0x%08lx, status = %02x\n", err, status);
3532c9bd703SFrançois Revol 		if (err < 0) return err;
3542c9bd703SFrançois Revol 		if (status & 0x04) return B_OK;
3552c9bd703SFrançois Revol 		//XXX:FIXME:spin((1+5+11*dev->sensor->use_400kHz)*8);
3562c9bd703SFrançois Revol 		snooze((1+5+11*Sensor()->Use400kHz())*8);
3572c9bd703SFrançois Revol 	}
3582c9bd703SFrançois Revol 	return EBUSY;
3592c9bd703SFrançois Revol }
3602c9bd703SFrançois Revol 
36174b3713aSFrançois Revol 
3622c9bd703SFrançois Revol ssize_t
WriteIIC(uint8 address,uint8 * data,size_t count)3632c9bd703SFrançois Revol SonixCamDevice::WriteIIC(uint8 address, uint8 *data, size_t count)
3642c9bd703SFrançois Revol {
3652c9bd703SFrançois Revol 	status_t err;
3662c9bd703SFrançois Revol 	uint8 buffer[8];
367*edb48467SMurai Takashi 	PRINT((CH "(%u, @%p, %" B_PRIuSIZE ")" CT, address, data, count));
368fb086488SFrançois Revol 
3692c9bd703SFrançois Revol 	if (!Sensor())
3702c9bd703SFrançois Revol 		return B_NO_INIT;
3712c9bd703SFrançois Revol 	//dprintf(ID "sonix_i2c_write_multi(, %02x, %d, {%02x, %02x, %02x, %02x, %02x})\n", slave, count, d0, d1, d2, d3, d4);
3722c9bd703SFrançois Revol 	count++; // includes address
3732c9bd703SFrançois Revol 	if (count > 5)
3742c9bd703SFrançois Revol 		return EINVAL;
375c38af24cSFrançois Revol 	buffer[0] = ((count) << 4) | (Sensor()->Use400kHz()?0x01:0)
376c38af24cSFrançois Revol 							 | (Sensor()->UseRealIIC()?0x80:0);
3772c9bd703SFrançois Revol 	buffer[1] = Sensor()->IICWriteAddress();
3782c9bd703SFrançois Revol 	buffer[2] = address;
3792c9bd703SFrançois Revol 	memset(&buffer[3], 0, 5);
380c38af24cSFrançois Revol 	memcpy(&buffer[3], data, count-1);
381fb086488SFrançois Revol 	buffer[7] = 0x16; /* V4L2 driver uses 0x10, XP driver uses 0x16 ? */
382c38af24cSFrançois Revol 	for (int i = 0; i < 8; i++) {
383c38af24cSFrançois Revol 		PRINT(("[%d] = %02x\n", i, buffer[i]));
384c38af24cSFrançois Revol 	}
3852c9bd703SFrançois Revol 	err = WriteReg(SN9C102_I2C_SETUP, buffer, 8);
3862c9bd703SFrançois Revol 	//dprintf(ID "sonix_i2c_write_multi: set_regs error 0x%08lx\n", err);
3872c9bd703SFrançois Revol 	//PRINT((CH ": WriteReg: %s" CT, strerror(err)));
3882c9bd703SFrançois Revol 	if (err < 0) return err;
3892c9bd703SFrançois Revol 	err = WaitReadyIIC();
3902c9bd703SFrançois Revol 	//dprintf(ID "sonix_i2c_write_multi: sonix_i2c_wait_ready error 0x%08lx\n", err);
3912c9bd703SFrançois Revol 	//PRINT((CH ": Wait: %s" CT, strerror(err)));
3922c9bd703SFrançois Revol 	if (err) return err;
3932c9bd703SFrançois Revol 	err = GetStatusIIC();
3942c9bd703SFrançois Revol 	//dprintf(ID "sonix_i2c_write_multi: sonix_i2c_status error 0x%08lx\n", err);
3952c9bd703SFrançois Revol 	//PRINT((CH ": Status: %s" CT, strerror(err)));
3962c9bd703SFrançois Revol 	if (err) return err;
3972c9bd703SFrançois Revol 	//dprintf(ID "sonix_i2c_write_multi: succeeded\n");
3982c9bd703SFrançois Revol 	PRINT((CH ": success" CT));
3992c9bd703SFrançois Revol 	return B_OK;
4002c9bd703SFrançois Revol }
4012c9bd703SFrançois Revol 
40274b3713aSFrançois Revol 
4032c9bd703SFrançois Revol ssize_t
ReadIIC(uint8 address,uint8 * data)4042c9bd703SFrançois Revol SonixCamDevice::ReadIIC(uint8 address, uint8 *data)
4052c9bd703SFrançois Revol {
4062c9bd703SFrançois Revol 	status_t err, lasterr = B_OK;
4072c9bd703SFrançois Revol 	uint8 buffer[8];
408fb086488SFrançois Revol 	PRINT((CH "(%u, @%p)" CT, address, data));
409fb086488SFrançois Revol 
4102c9bd703SFrançois Revol 	if (!Sensor())
4112c9bd703SFrançois Revol 		return B_NO_INIT;
4122c9bd703SFrançois Revol 	//dprintf(ID "sonix_i2c_write_multi(, %02x, %d, {%02x, %02x, %02x, %02x, %02x})\n", slave, count, d0, d1, d2, d3, d4);
413cb1f2e65SPhilippe Saint-Pierre 	buffer[0] = (1 << 4) | (Sensor()->Use400kHz()?0x01:0)
414cb1f2e65SPhilippe Saint-Pierre 						| (Sensor()->UseRealIIC()?0x80:0);
4152c9bd703SFrançois Revol 	buffer[1] = Sensor()->IICWriteAddress();
4162c9bd703SFrançois Revol 	buffer[2] = address;
4172c9bd703SFrançois Revol 	buffer[7] = 0x10; /* absolutely no idea why V4L2 driver use that value */
4182c9bd703SFrançois Revol 	err = WriteReg(SN9C102_I2C_SETUP, buffer, 8);
4192c9bd703SFrançois Revol 	//dprintf(ID "sonix_i2c_write_multi: set_regs error 0x%08lx\n", err);
420fb086488SFrançois Revol 	if (err < 8) return EIO;
4212c9bd703SFrançois Revol 	err = WaitReadyIIC();
4222c9bd703SFrançois Revol 	//dprintf(ID "sonix_i2c_write_multi: sonix_i2c_wait_ready error 0x%08lx\n", err);
4232c9bd703SFrançois Revol 	//if (err) return err;
4242c9bd703SFrançois Revol 
4252c9bd703SFrançois Revol 
4262c9bd703SFrançois Revol 	//dprintf(ID "sonix_i2c_write_multi(, %02x, %d, {%02x, %02x, %02x, %02x, %02x})\n", slave, count, d0, d1, d2, d3, d4);
427cb1f2e65SPhilippe Saint-Pierre 	buffer[0] = (1 << 4) | (Sensor()->Use400kHz()?0x01:0)
428cb1f2e65SPhilippe Saint-Pierre 				  | 0x02 | (Sensor()->UseRealIIC()?0x80:0); /* read 1 byte */
4292c9bd703SFrançois Revol 	buffer[1] = Sensor()->IICReadAddress();//IICWriteAddress
4302c9bd703SFrançois Revol 	buffer[7] = 0x10; /* absolutely no idea why V4L2 driver use that value */
4312c9bd703SFrançois Revol 	err = WriteReg(SN9C102_I2C_SETUP, buffer, 8);
4322c9bd703SFrançois Revol 	//dprintf(ID "sonix_i2c_write_multi: set_regs error 0x%08lx\n", err);
433fb086488SFrançois Revol 	if (err < 8) return EIO;
4342c9bd703SFrançois Revol 	err = WaitReadyIIC();
4352c9bd703SFrançois Revol 	//dprintf(ID "sonix_i2c_write_multi: sonix_i2c_wait_ready error 0x%08lx\n", err);
436fb086488SFrançois Revol 	if (err < B_OK) return err;
4372c9bd703SFrançois Revol 
4382c9bd703SFrançois Revol 	err = ReadReg(SN9C102_I2C_DATA0, buffer, 5);
439fb086488SFrançois Revol 	if (err < 5) return EIO;
4402c9bd703SFrançois Revol 
4412c9bd703SFrançois Revol 	err = GetStatusIIC();
4422c9bd703SFrançois Revol 	//dprintf(ID "sonix_i2c_write_multi: sonix_i2c_status error 0x%08lx\n", err);
443fb086488SFrançois Revol 	if (err < B_OK) return err;
4442c9bd703SFrançois Revol 	//dprintf(ID "sonix_i2c_write_multi: succeeded\n");
4452c9bd703SFrançois Revol 	if (lasterr) return err;
4462c9bd703SFrançois Revol 
4472c9bd703SFrançois Revol 	/* we should get what we want in buffer[4] according to the V4L2 driver...
4482c9bd703SFrançois Revol 	 * probably because the 5 bytes are a bit shift register?
4492c9bd703SFrançois Revol 	 */
4502c9bd703SFrançois Revol 	*data = buffer[4];
4512c9bd703SFrançois Revol 
4522c9bd703SFrançois Revol 	return 1;
4532c9bd703SFrançois Revol }
4542c9bd703SFrançois Revol 
45574b3713aSFrançois Revol 
4562c9bd703SFrançois Revol status_t
SetVideoFrame(BRect frame)4572c9bd703SFrançois Revol SonixCamDevice::SetVideoFrame(BRect frame)
4582c9bd703SFrançois Revol {
4592c9bd703SFrançois Revol 	uint16 x, y, width, height;
4602c9bd703SFrançois Revol 	x = (uint16)frame.left;
4612c9bd703SFrançois Revol 	y = (uint16)frame.top;
4622c9bd703SFrançois Revol 	width = (uint16)(frame.right - frame.left + 1) / 16;
4632c9bd703SFrançois Revol 	height = (uint16)(frame.bottom - frame.top + 1) / 16;
4642c9bd703SFrançois Revol 	PRINT((CH "(%u, %u, %u, %u)" CT, x, y, width, height));
4652c9bd703SFrançois Revol 
4662c9bd703SFrançois Revol 	WriteReg8(SN9C102_H_START, x);
4672c9bd703SFrançois Revol 	WriteReg8(SN9C102_V_START, y);
4682c9bd703SFrançois Revol 	WriteReg8(SN9C102_H_SIZE, width);
4692c9bd703SFrançois Revol 	WriteReg8(SN9C102_V_SIZE, height);
4702c9bd703SFrançois Revol 	if (Sensor()) {
4712c9bd703SFrançois Revol 		Sensor()->SetVideoFrame(frame);
4722c9bd703SFrançois Revol 	}
4732c9bd703SFrançois Revol 	return CamDevice::SetVideoFrame(frame);
4742c9bd703SFrançois Revol }
4752c9bd703SFrançois Revol 
47674b3713aSFrançois Revol 
4772c9bd703SFrançois Revol status_t
SetScale(float scale)4782c9bd703SFrançois Revol SonixCamDevice::SetScale(float scale)
4792c9bd703SFrançois Revol {
4802c9bd703SFrançois Revol 	status_t err;
4812c9bd703SFrançois Revol 	uint8 r;
4822c9bd703SFrançois Revol 	int iscale = (int)scale;
4832c9bd703SFrançois Revol 
4842c9bd703SFrançois Revol 	PRINT((CH "(%u)" CT, iscale));
4852c9bd703SFrançois Revol 	err = ReadReg(SN9C102_SYNC_N_SCALE, &r, 1, true);
4862c9bd703SFrançois Revol 	if (err < 0)
4872c9bd703SFrançois Revol 		return err;
4882c9bd703SFrançois Revol 	r &= ~0x30;
4892c9bd703SFrançois Revol 	switch (iscale) {
4902c9bd703SFrançois Revol 	case 1:
4912c9bd703SFrançois Revol 	case 2:
4922c9bd703SFrançois Revol 	case 4:
4932c9bd703SFrançois Revol 		r |= ((iscale-1) << 4);
4942c9bd703SFrançois Revol 		break;
4952c9bd703SFrançois Revol 	default:
4962c9bd703SFrançois Revol 		return EINVAL;
4972c9bd703SFrançois Revol 	}
4982c9bd703SFrançois Revol 	err = WriteReg8(SN9C102_SYNC_N_SCALE, r);
4992c9bd703SFrançois Revol 	return err;
5002c9bd703SFrançois Revol }
5012c9bd703SFrançois Revol 
50274b3713aSFrançois Revol 
5032c9bd703SFrançois Revol status_t
SetVideoParams(float brightness,float contrast,float hue,float red,float green,float blue)5042c9bd703SFrançois Revol SonixCamDevice::SetVideoParams(float brightness, float contrast, float hue, float red, float green, float blue)
5052c9bd703SFrançois Revol {
5062c9bd703SFrançois Revol 	return B_OK;
5072c9bd703SFrançois Revol }
5082c9bd703SFrançois Revol 
509a486abdcSFrançois Revol void
AddParameters(BParameterGroup * group,int32 & index)510a486abdcSFrançois Revol SonixCamDevice::AddParameters(BParameterGroup *group, int32 &index)
511a486abdcSFrançois Revol {
512c38af24cSFrançois Revol 	BParameterGroup *g;
513a486abdcSFrançois Revol 	BContinuousParameter *p;
514a486abdcSFrançois Revol 	CamDevice::AddParameters(group, index);
515a486abdcSFrançois Revol 
516c38af24cSFrançois Revol 	// R,G,B gains
517c38af24cSFrançois Revol 	g = group->MakeGroup("RGB gain");
518c38af24cSFrançois Revol 	p = g->MakeContinuousParameter(index++,
519a486abdcSFrançois Revol 		B_MEDIA_RAW_VIDEO, "RGB gain",
520a486abdcSFrançois Revol 		B_GAIN, "", 1.0, 1.0+(float)(SN9C102_RGB_GAIN_MAX)/8, (float)1.0/8);
521a486abdcSFrançois Revol 
522a486abdcSFrançois Revol 	p->SetChannelCount(3);
523c38af24cSFrançois Revol #if 0
524c38af24cSFrançois Revol 	// Contrast - NON FUNCTIONAL
525c38af24cSFrançois Revol 	g = group->MakeGroup("Contrast");
526c38af24cSFrançois Revol 	p = g->MakeContinuousParameter(index++,
527c38af24cSFrançois Revol 		B_MEDIA_RAW_VIDEO, "Contrast",
528c38af24cSFrançois Revol 		B_GAIN, "", 0.0, 1.0, 1.0/256);
529a486abdcSFrançois Revol 
530c38af24cSFrançois Revol 	// Brightness - NON FUNCTIONAL
531c38af24cSFrançois Revol 	g = group->MakeGroup("Brightness");
532c38af24cSFrançois Revol 	p = g->MakeContinuousParameter(index++,
533c38af24cSFrançois Revol 		B_MEDIA_RAW_VIDEO, "Brightness",
534c38af24cSFrançois Revol 		B_GAIN, "", 0.0, 1.0, 1.0/256);
535a486abdcSFrançois Revol 
536c38af24cSFrançois Revol #endif
537a486abdcSFrançois Revol }
538a486abdcSFrançois Revol 
539a486abdcSFrançois Revol status_t
GetParameterValue(int32 id,bigtime_t * last_change,void * value,size_t * size)540a486abdcSFrançois Revol SonixCamDevice::GetParameterValue(int32 id, bigtime_t *last_change, void *value, size_t *size)
541a486abdcSFrançois Revol {
542a486abdcSFrançois Revol 	float *gains;
543a486abdcSFrançois Revol 	switch (id - fFirstParameterID) {
544a486abdcSFrançois Revol 		case 0:
545a486abdcSFrançois Revol 			*size = 3 * sizeof(float);
546a486abdcSFrançois Revol 			gains = ((float *)value);
547a486abdcSFrançois Revol 			gains[0] = 1.0 + (float)fRGain / 8;
548a486abdcSFrançois Revol 			gains[1] = 1.0 + (float)fGGain / 8;
549a486abdcSFrançois Revol 			gains[2] = 1.0 + (float)fBGain / 8;
550a486abdcSFrançois Revol 			*last_change = fLastParameterChanges;
551a486abdcSFrançois Revol 			return B_OK;
552c38af24cSFrançois Revol #if 0
553c38af24cSFrançois Revol 		case 1:
554c38af24cSFrançois Revol 			*size = sizeof(float);
555c38af24cSFrançois Revol 			gains = ((float *)value);
556c38af24cSFrançois Revol 			gains[0] = fContrast;
557c38af24cSFrançois Revol 			*last_change = fLastParameterChanges;
558c38af24cSFrançois Revol 			return B_OK;
559c38af24cSFrançois Revol 		case 2:
560c38af24cSFrançois Revol 			*size = sizeof(float);
561c38af24cSFrançois Revol 			gains = ((float *)value);
562c38af24cSFrançois Revol 			gains[0] = fBrightness;
563c38af24cSFrançois Revol 			*last_change = fLastParameterChanges;
564c38af24cSFrançois Revol 			return B_OK;
565c38af24cSFrançois Revol #endif
566a486abdcSFrançois Revol 	}
567a486abdcSFrançois Revol 	return B_BAD_VALUE;
568a486abdcSFrançois Revol }
569a486abdcSFrançois Revol 
570a486abdcSFrançois Revol status_t
SetParameterValue(int32 id,bigtime_t when,const void * value,size_t size)571a486abdcSFrançois Revol SonixCamDevice::SetParameterValue(int32 id, bigtime_t when, const void *value, size_t size)
572a486abdcSFrançois Revol {
573a486abdcSFrançois Revol 	float *gains;
574a486abdcSFrançois Revol 	switch (id - fFirstParameterID) {
575a486abdcSFrançois Revol 		case 0:
576a486abdcSFrançois Revol 			if (!value || (size != 3 * sizeof(float)))
577a486abdcSFrançois Revol 				return B_BAD_VALUE;
578a486abdcSFrançois Revol 			gains = ((float *)value);
579a486abdcSFrançois Revol 			if ((gains[0] == 1.0 + (float)fRGain / 8)
580a486abdcSFrançois Revol 				&& (gains[1] == 1.0 + (float)fGGain / 8)
581a486abdcSFrançois Revol 				&& (gains[2] == 1.0 + (float)fBGain / 8))
582a486abdcSFrançois Revol 				return B_OK;
583a486abdcSFrançois Revol 
584a486abdcSFrançois Revol 			fRGain = (int)(8 * (gains[0] - 1.0)) & SN9C102_RGB_GAIN_MAX;
585a486abdcSFrançois Revol 			fGGain = (int)(8 * (gains[1] - 1.0)) & SN9C102_RGB_GAIN_MAX;
586a486abdcSFrançois Revol 			fBGain = (int)(8 * (gains[2] - 1.0)) & SN9C102_RGB_GAIN_MAX;
587a486abdcSFrançois Revol 			fLastParameterChanges = when;
588a486abdcSFrançois Revol 			PRINT((CH ": gain: %d,%d,%d" CT, fRGain, fGGain, fBGain));
589a486abdcSFrançois Revol 			//WriteReg8(SN9C102_R_B_GAIN, (fBGain << 4) | fRGain);	/* red, blue gain = 1+0/8 = 1 */
590a486abdcSFrançois Revol 			/* Datasheet says:
591a486abdcSFrançois Revol 			 * reg 0x10 [0:3] is rgain, [4:7] is bgain and 0x11 [0:3] is ggain
592a486abdcSFrançois Revol 			 * according to sn9c102-1.15 linux driver it's wrong for reg 0x10,
593a486abdcSFrançois Revol 			 * but it doesn't seem to work any better for a rev 2 chip.
594a486abdcSFrançois Revol 			 * XXX
595a486abdcSFrançois Revol 			 */
5965b880818SFrançois Revol #if 1
597a486abdcSFrançois Revol 			WriteReg8(SN9C102_R_GAIN, fRGain);
598a486abdcSFrançois Revol 			WriteReg8(SN9C102_B_GAIN, fBGain);
599a486abdcSFrançois Revol 			if (fChipVersion >= 3)
600a486abdcSFrançois Revol 				WriteReg8(SN9C103_G_GAIN, fGGain);
601a486abdcSFrançois Revol 			else
602a486abdcSFrançois Revol 				WriteReg8(SN9C102_G_GAIN, (fGGain / 16));
6035b880818SFrançois Revol #endif
6045b880818SFrançois Revol #if 0
6055b880818SFrançois Revol 			uint8 buf[2];
6065b880818SFrançois Revol 			buf[0] = (fBGain << 4) | fRGain;
6075b880818SFrançois Revol 			buf[1] = fGGain;
6085b880818SFrançois Revol 			WriteReg(SN9C102_R_B_GAIN, buf, 2);
6095b880818SFrançois Revol #endif
610a486abdcSFrançois Revol 			return B_OK;
611c38af24cSFrançois Revol #if 0
612c38af24cSFrançois Revol 		case 1:
613c38af24cSFrançois Revol 			if (!value || (size != sizeof(float)))
614c38af24cSFrançois Revol 				return B_BAD_VALUE;
615c38af24cSFrançois Revol 			gains = ((float *)value);
616c38af24cSFrançois Revol 			fContrast = gains[0];
617c38af24cSFrançois Revol 			WriteReg8(SN9C10x_CONTRAST, ((uint8)(fContrast * 256)));
618c38af24cSFrançois Revol 			return B_OK;
619c38af24cSFrançois Revol 		case 2:
620c38af24cSFrançois Revol 			if (!value || (size != sizeof(float)))
621c38af24cSFrançois Revol 				return B_BAD_VALUE;
622c38af24cSFrançois Revol 			gains = ((float *)value);
623c38af24cSFrançois Revol 			fBrightness = gains[0];
624c38af24cSFrançois Revol 			// it actually ends up writing to SN9C102_V_SIZE...
625c38af24cSFrançois Revol 			WriteReg8(SN9C10x_BRIGHTNESS, ((uint8)(fBrightness * 256)));
626c38af24cSFrançois Revol 
627c38af24cSFrançois Revol 			return B_OK;
628c38af24cSFrançois Revol #endif
629a486abdcSFrançois Revol 	}
630a486abdcSFrançois Revol 	return B_BAD_VALUE;
631a486abdcSFrançois Revol }
632a486abdcSFrançois Revol 
633a486abdcSFrançois Revol 
63474b3713aSFrançois Revol 
6352c9bd703SFrançois Revol size_t
MinRawFrameSize()6362c9bd703SFrançois Revol SonixCamDevice::MinRawFrameSize()
6372c9bd703SFrançois Revol {
6382c9bd703SFrançois Revol 	// if (fCompressionEnabled) { ... return ; }
6392c9bd703SFrançois Revol 	BRect vf(VideoFrame());
64072bfb144SAdrien Destugues 	size_t w = vf.IntegerWidth()+1;
64172bfb144SAdrien Destugues 	size_t h = vf.IntegerHeight()+1;
6422c9bd703SFrançois Revol 	// 1 byte/pixel
64372bfb144SAdrien Destugues 	return w * h;
6442c9bd703SFrançois Revol }
6452c9bd703SFrançois Revol 
64674b3713aSFrançois Revol 
6472c9bd703SFrançois Revol size_t
MaxRawFrameSize()6482c9bd703SFrançois Revol SonixCamDevice::MaxRawFrameSize()
6492c9bd703SFrançois Revol {
6502c9bd703SFrançois Revol 	// if (fCompressionEnabled) { ... return ; }
6512c9bd703SFrançois Revol 	return MinRawFrameSize()+1024*0; // fixed size frame (uncompressed)
6522c9bd703SFrançois Revol }
6532c9bd703SFrançois Revol 
65474b3713aSFrançois Revol 
6552c9bd703SFrançois Revol bool
ValidateStartOfFrameTag(const uint8 * tag,size_t taglen)6562c9bd703SFrançois Revol SonixCamDevice::ValidateStartOfFrameTag(const uint8 *tag, size_t taglen)
6572c9bd703SFrançois Revol {
6582c9bd703SFrançois Revol 	// SOF come with an 00, 40, 80, C0 sequence,
6592c9bd703SFrançois Revol 	// supposedly corresponding with an equal byte in the end tag
6602c9bd703SFrançois Revol 	fFrameTagState = tag[7] & 0xC0;
661*edb48467SMurai Takashi 	PRINT((CH "(, %" B_PRIuSIZE ") state %x" CT, taglen, fFrameTagState));
6622c9bd703SFrançois Revol 
6632c9bd703SFrançois Revol 	// which seems to be the same as of the EOF tag
6642c9bd703SFrançois Revol 	return true;
6652c9bd703SFrançois Revol }
6662c9bd703SFrançois Revol 
66774b3713aSFrançois Revol 
6682c9bd703SFrançois Revol bool
ValidateEndOfFrameTag(const uint8 * tag,size_t taglen,size_t datalen)6692c9bd703SFrançois Revol SonixCamDevice::ValidateEndOfFrameTag(const uint8 *tag, size_t taglen, size_t datalen)
6702c9bd703SFrançois Revol {
6712c9bd703SFrançois Revol 	//PRINT((CH "(, %d) %x == %x" CT, taglen, (tag[0] & 0xC0), fFrameTagState));
6722c9bd703SFrançois Revol 	// make sure the tag corresponds to the SOF we refer to
6732c9bd703SFrançois Revol 	if ((tag[0] & 0xC0) != fFrameTagState) {
6742c9bd703SFrançois Revol 		PRINT((CH ": discarded EOF %x != %x" CT, fFrameTagState, tag[0] & 0xC0));
6752c9bd703SFrançois Revol 		return false;
6762c9bd703SFrançois Revol 	}
6772c9bd703SFrançois Revol 	//PRINT((CH ": validated EOF %x, len %d" CT, fFrameTagState, datalen));
6782c9bd703SFrançois Revol 	return true;
6792c9bd703SFrançois Revol }
6802c9bd703SFrançois Revol 
68174b3713aSFrançois Revol 
6822c9bd703SFrançois Revol status_t
GetFrameBitmap(BBitmap ** bm,bigtime_t * stamp)6831f1863e2SMarcus Overhagen SonixCamDevice::GetFrameBitmap(BBitmap **bm, bigtime_t *stamp /* = NULL */)
6842c9bd703SFrançois Revol {
6852c9bd703SFrançois Revol 	BBitmap *b;
6862c9bd703SFrançois Revol 	CamFrame *f;
6872c9bd703SFrançois Revol 	status_t err;
6882c9bd703SFrançois Revol 	PRINT((CH "()" CT));
6892c9bd703SFrançois Revol 	err = fDeframer->WaitFrame(200000);
6902c9bd703SFrançois Revol 	if (err < B_OK) { PRINT((CH ": WaitFrame: %s" CT, strerror(err))); }
6912c9bd703SFrançois Revol 	if (err < B_OK)
6922c9bd703SFrançois Revol 		return err;
6936bb8b29fSFrançois Revol 	err = fDeframer->GetFrame(&f, stamp);
6942c9bd703SFrançois Revol 	if (err < B_OK) { PRINT((CH ": GetFrame: %s" CT, strerror(err))); }
6952c9bd703SFrançois Revol 	if (err < B_OK)
6962c9bd703SFrançois Revol 		return err;
6972c9bd703SFrançois Revol 	PRINT((CH ": VideoFrame = %fx%f,%fx%f" CT, VideoFrame().left, VideoFrame().top, VideoFrame().right, VideoFrame().bottom));
6982c9bd703SFrançois Revol 
699e53032e5SFrançois Revol 	long int w = (long)(VideoFrame().right - VideoFrame().left + 1);
700e53032e5SFrançois Revol 	long int h = (long)(VideoFrame().bottom - VideoFrame().top + 1);
7012c9bd703SFrançois Revol 	b = new BBitmap(VideoFrame().OffsetToSelf(0,0), 0, B_RGB32, w*4);
702*edb48467SMurai Takashi 	PRINT((CH ": Frame: %ldx%ld" CT, w, h));
7032c9bd703SFrançois Revol 
7042c9bd703SFrançois Revol 	bayer2rgb24((unsigned char *)b->Bits(), (unsigned char *)f->Buffer(), w, h);
7052c9bd703SFrançois Revol 
7062c9bd703SFrançois Revol 	PRINT((CH ": got 1 frame (len %d)" CT, b->BitsLength()));
7072c9bd703SFrançois Revol 	*bm = b;
7082c9bd703SFrançois Revol 	return B_OK;
7092c9bd703SFrançois Revol }
7102c9bd703SFrançois Revol 
71174b3713aSFrançois Revol 
7122c9bd703SFrançois Revol status_t
FillFrameBuffer(BBuffer * buffer,bigtime_t * stamp)7136bb8b29fSFrançois Revol SonixCamDevice::FillFrameBuffer(BBuffer *buffer, bigtime_t *stamp)
7142c9bd703SFrançois Revol {
7152c9bd703SFrançois Revol 	CamFrame *f;
7162c9bd703SFrançois Revol 	status_t err;
7172c9bd703SFrançois Revol 	PRINT((CH "()" CT));
7182c9bd703SFrançois Revol 
7192c9bd703SFrançois Revol 	memset(buffer->Data(), 0, buffer->SizeAvailable());
7202c9bd703SFrançois Revol 	err = fDeframer->WaitFrame(2000000);
7212c9bd703SFrançois Revol 	if (err < B_OK) { PRINT((CH ": WaitFrame: %s" CT, strerror(err))); }
7222c9bd703SFrançois Revol 	if (err < B_OK)
7232c9bd703SFrançois Revol 		return err;
7242c9bd703SFrançois Revol 
7256bb8b29fSFrançois Revol 	err = fDeframer->GetFrame(&f, stamp);
7262c9bd703SFrançois Revol 	if (err < B_OK) { PRINT((CH ": GetFrame: %s" CT, strerror(err))); }
7272c9bd703SFrançois Revol 	if (err < B_OK)
7282c9bd703SFrançois Revol 		return err;
7292c9bd703SFrançois Revol 
730e53032e5SFrançois Revol 	long int w = (long)(VideoFrame().right - VideoFrame().left + 1);
731e53032e5SFrançois Revol 	long int h = (long)(VideoFrame().bottom - VideoFrame().top + 1);
732*edb48467SMurai Takashi 	PRINT((CH ": VideoFrame = %fx%f,%fx%f Frame: %ldx%ld" CT,
733*edb48467SMurai Takashi 		VideoFrame().left, VideoFrame().top, VideoFrame().right,
734*edb48467SMurai Takashi 		VideoFrame().bottom, w, h));
7352c9bd703SFrançois Revol 
736e53032e5SFrançois Revol 	if (buffer->SizeAvailable() >= (size_t)w*h*4)
7372c9bd703SFrançois Revol 		bayer2rgb32le((unsigned char *)buffer->Data(), (unsigned char *)f->Buffer(), w, h);
7382c9bd703SFrançois Revol 
7392c9bd703SFrançois Revol 	delete f;
7402c9bd703SFrançois Revol 
741*edb48467SMurai Takashi 	PRINT((CH ": available %" B_PRIuSIZE ", required %ld" CT,
742*edb48467SMurai Takashi 		buffer->SizeAvailable(), w*h*4));
743e53032e5SFrançois Revol 	if (buffer->SizeAvailable() < (size_t)w*h*4)
7442c9bd703SFrançois Revol 		return E2BIG;
745*edb48467SMurai Takashi 	PRINT((CH ": got 1 frame (len %" B_PRIuSIZE ")" CT, buffer->SizeUsed()));
7462c9bd703SFrançois Revol 	return B_OK;
7472c9bd703SFrançois Revol }
7482c9bd703SFrançois Revol 
74974b3713aSFrançois Revol 
7502c9bd703SFrançois Revol void
7512c9bd703SFrançois Revol /* DEBUG: dump the SN regs */
DumpRegs()7522c9bd703SFrançois Revol SonixCamDevice::DumpRegs()
7532c9bd703SFrançois Revol {
7542c9bd703SFrançois Revol 	uint8 regs[SN9C102_REG_COUNT];
7552c9bd703SFrançois Revol 	status_t err;
7562c9bd703SFrançois Revol 
7572c9bd703SFrançois Revol 	//err = sonix_get_regs(dev, SN_ASIC_ID, regs, SN_REG_COUNT);
7582c9bd703SFrançois Revol 	err = ReadReg(0, regs, SN9C102_REG_COUNT);
7592c9bd703SFrançois Revol 	if (err < 0)
7602c9bd703SFrançois Revol 		return;
7612c9bd703SFrançois Revol 	printf("REG1: %02x %02x %02x %02x  %02x %02x %02x %02x\n",
7622c9bd703SFrançois Revol 			regs[0], regs[1], regs[2], regs[3], regs[4], regs[5], regs[6], regs[7]);
7632c9bd703SFrançois Revol 	printf("   2: %02x %02x %02x %02x  %02x %02x %02x %02x\n",
7642c9bd703SFrançois Revol 			regs[8], regs[9], regs[10], regs[11], regs[12], regs[13], regs[14], regs[15]);
7652c9bd703SFrançois Revol 	printf("   3: %02x %02x %02x %02x  %02x %02x %02x %02x\n",
7662c9bd703SFrançois Revol 			regs[16], regs[17], regs[18], regs[19], regs[20], regs[21], regs[22], regs[23]);
7672c9bd703SFrançois Revol 	printf("   4: %02x %02x %02x %02x  %02x %02x %02x %02x\n",
7682c9bd703SFrançois Revol 			regs[24], regs[25], regs[26], regs[27], regs[28], regs[29], regs[30], regs[31]);
7692c9bd703SFrançois Revol }
7702c9bd703SFrançois Revol 
7715b880818SFrançois Revol #if 0
77274b3713aSFrançois Revol 
7732c9bd703SFrançois Revol status_t
7742c9bd703SFrançois Revol SonixCamDevice::SendCommand(uint8 dir, uint8 request, uint16 value,
7752c9bd703SFrançois Revol 							uint16 index, uint16 length, void* data)
7762c9bd703SFrançois Revol {
7772c9bd703SFrançois Revol 	size_t ret;
7782c9bd703SFrançois Revol 	if (!GetDevice())
7792c9bd703SFrançois Revol 		return ENODEV;
7805b880818SFrançois Revol 	if (length > GetDevice()->MaxEndpoint0PacketSize())
7815b880818SFrançois Revol 		return EINVAL;
7822c9bd703SFrançois Revol 	ret = GetDevice()->ControlTransfer(
7832c9bd703SFrançois Revol 				USB_REQTYPE_VENDOR | USB_REQTYPE_INTERFACE_OUT | dir,
7842c9bd703SFrançois Revol 				request, value, index, length, data);
7852c9bd703SFrançois Revol 	return ret;
7862c9bd703SFrançois Revol }
7875b880818SFrançois Revol #endif
7882c9bd703SFrançois Revol 
78974b3713aSFrançois Revol 
SonixCamDeviceAddon(WebCamMediaAddOn * webcam)7902c9bd703SFrançois Revol SonixCamDeviceAddon::SonixCamDeviceAddon(WebCamMediaAddOn* webcam)
7912c9bd703SFrançois Revol 	: CamDeviceAddon(webcam)
7922c9bd703SFrançois Revol {
7932c9bd703SFrançois Revol 	SetSupportedDevices(kSupportedDevices);
7942c9bd703SFrançois Revol }
7952c9bd703SFrançois Revol 
79674b3713aSFrançois Revol 
~SonixCamDeviceAddon()7972c9bd703SFrançois Revol SonixCamDeviceAddon::~SonixCamDeviceAddon()
7982c9bd703SFrançois Revol {
7992c9bd703SFrançois Revol }
8002c9bd703SFrançois Revol 
80174b3713aSFrançois Revol 
8022c9bd703SFrançois Revol const char *
BrandName()8032c9bd703SFrançois Revol SonixCamDeviceAddon::BrandName()
8042c9bd703SFrançois Revol {
8052c9bd703SFrançois Revol 	return "Sonix";
8062c9bd703SFrançois Revol }
8072c9bd703SFrançois Revol 
80874b3713aSFrançois Revol 
8092c9bd703SFrançois Revol SonixCamDevice *
Instantiate(CamRoster & roster,BUSBDevice * from)8102c9bd703SFrançois Revol SonixCamDeviceAddon::Instantiate(CamRoster &roster, BUSBDevice *from)
8112c9bd703SFrançois Revol {
8122c9bd703SFrançois Revol 	return new SonixCamDevice(*this, from);
8132c9bd703SFrançois Revol }
8142c9bd703SFrançois Revol 
8152c9bd703SFrançois Revol extern "C" status_t
B_WEBCAM_MKINTFUNC(sonix)8162c9bd703SFrançois Revol B_WEBCAM_MKINTFUNC(sonix)
8172c9bd703SFrançois Revol (WebCamMediaAddOn* webcam, CamDeviceAddon **addon)
8182c9bd703SFrançois Revol {
8192c9bd703SFrançois Revol 	*addon = new SonixCamDeviceAddon(webcam);
8202c9bd703SFrançois Revol 	return B_OK;
8212c9bd703SFrançois Revol }
8222c9bd703SFrançois Revol 
8232c9bd703SFrançois Revol // XXX: REMOVE ME
8242c9bd703SFrançois Revol 
8252c9bd703SFrançois Revol 
8262c9bd703SFrançois Revol 
8272c9bd703SFrançois Revol /*
8282c9bd703SFrançois Revol  * BAYER2RGB24 ROUTINE TAKEN FROM:
8292c9bd703SFrançois Revol  *
8302c9bd703SFrançois Revol  * Sonix SN9C101 based webcam basic I/F routines
8312c9bd703SFrançois Revol  * Copyright (C) 2004 Takafumi Mizuno <taka-qce@ls-a.jp>
8322c9bd703SFrançois Revol  *
8332c9bd703SFrançois Revol  * Redistribution and use in source and binary forms, with or without
8342c9bd703SFrançois Revol  * modification, are permitted provided that the following conditions
8352c9bd703SFrançois Revol  * are met:
8362c9bd703SFrançois Revol  * 1. Redistributions of source code must retain the above copyright
8372c9bd703SFrançois Revol  *    notice, this list of conditions and the following disclaimer.
8382c9bd703SFrançois Revol  * 2. Redistributions in binary form must reproduce the above copyright
8392c9bd703SFrançois Revol  *    notice, this list of conditions and the following disclaimer in the
8402c9bd703SFrançois Revol  *    documentation and/or other materials provided with the distribution.
8412c9bd703SFrançois Revol  *
8422c9bd703SFrançois Revol  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
8432c9bd703SFrançois Revol  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
8442c9bd703SFrançois Revol  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
8452c9bd703SFrançois Revol  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
8462c9bd703SFrançois Revol  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
8472c9bd703SFrançois Revol  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
8482c9bd703SFrançois Revol  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
8492c9bd703SFrançois Revol  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
8502c9bd703SFrançois Revol  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
8512c9bd703SFrançois Revol  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
8522c9bd703SFrançois Revol  * SUCH DAMAGE.
8532c9bd703SFrançois Revol  */
8542c9bd703SFrançois Revol 
bayer2rgb24(unsigned char * dst,unsigned char * src,long int WIDTH,long int HEIGHT)8552c9bd703SFrançois Revol void bayer2rgb24(unsigned char *dst, unsigned char *src, long int WIDTH, long int HEIGHT)
8562c9bd703SFrançois Revol {
8572c9bd703SFrançois Revol     long int i;
8582c9bd703SFrançois Revol     unsigned char *rawpt, *scanpt;
8592c9bd703SFrançois Revol     long int size;
8602c9bd703SFrançois Revol 
8612c9bd703SFrançois Revol     rawpt = src;
8622c9bd703SFrançois Revol     scanpt = dst;
8632c9bd703SFrançois Revol     size = WIDTH*HEIGHT;
8642c9bd703SFrançois Revol 
8652c9bd703SFrançois Revol     for ( i = 0; i < size; i++ ) {
8662c9bd703SFrançois Revol 	if ( (i/WIDTH) % 2 == 0 ) {
8672c9bd703SFrançois Revol 	    if ( (i % 2) == 0 ) {
8682c9bd703SFrançois Revol 		/* B */
8692c9bd703SFrançois Revol 		if ( (i > WIDTH) && ((i % WIDTH) > 0) ) {
8702c9bd703SFrançois Revol 		    *scanpt++ = (*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+
8712c9bd703SFrançois Revol 				 *(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4;	/* R */
8722c9bd703SFrançois Revol 		    *scanpt++ = (*(rawpt-1)+*(rawpt+1)+
8732c9bd703SFrançois Revol 				 *(rawpt+WIDTH)+*(rawpt-WIDTH))/4;	/* G */
8742c9bd703SFrançois Revol 		    *scanpt++ = *rawpt;					/* B */
8752c9bd703SFrançois Revol 		} else {
8762c9bd703SFrançois Revol 		    /* first line or left column */
8772c9bd703SFrançois Revol 		    *scanpt++ = *(rawpt+WIDTH+1);		/* R */
8782c9bd703SFrançois Revol 		    *scanpt++ = (*(rawpt+1)+*(rawpt+WIDTH))/2;	/* G */
8792c9bd703SFrançois Revol 		    *scanpt++ = *rawpt;				/* B */
8802c9bd703SFrançois Revol 		}
8812c9bd703SFrançois Revol 	    } else {
8822c9bd703SFrançois Revol 		/* (B)G */
8832c9bd703SFrançois Revol 		if ( (i > WIDTH) && ((i % WIDTH) < (WIDTH-1)) ) {
8842c9bd703SFrançois Revol 		    *scanpt++ = (*(rawpt+WIDTH)+*(rawpt-WIDTH))/2;	/* R */
8852c9bd703SFrançois Revol 		    *scanpt++ = *rawpt;					/* G */
8862c9bd703SFrançois Revol 		    *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2;		/* B */
8872c9bd703SFrançois Revol 		} else {
8882c9bd703SFrançois Revol 		    /* first line or right column */
8892c9bd703SFrançois Revol 		    *scanpt++ = *(rawpt+WIDTH);	/* R */
8902c9bd703SFrançois Revol 		    *scanpt++ = *rawpt;		/* G */
8912c9bd703SFrançois Revol 		    *scanpt++ = *(rawpt-1);	/* B */
8922c9bd703SFrançois Revol 		}
8932c9bd703SFrançois Revol 	    }
8942c9bd703SFrançois Revol 	} else {
8952c9bd703SFrançois Revol 	    if ( (i % 2) == 0 ) {
8962c9bd703SFrançois Revol 		/* G(R) */
8972c9bd703SFrançois Revol 		if ( (i < (WIDTH*(HEIGHT-1))) && ((i % WIDTH) > 0) ) {
8982c9bd703SFrançois Revol 		    *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2;		/* R */
8992c9bd703SFrançois Revol 		    *scanpt++ = *rawpt;					/* G */
9002c9bd703SFrançois Revol 		    *scanpt++ = (*(rawpt+WIDTH)+*(rawpt-WIDTH))/2;	/* B */
9012c9bd703SFrançois Revol 		} else {
9022c9bd703SFrançois Revol 		    /* bottom line or left column */
9032c9bd703SFrançois Revol 		    *scanpt++ = *(rawpt+1);		/* R */
9042c9bd703SFrançois Revol 		    *scanpt++ = *rawpt;			/* G */
9052c9bd703SFrançois Revol 		    *scanpt++ = *(rawpt-WIDTH);		/* B */
9062c9bd703SFrançois Revol 		}
9072c9bd703SFrançois Revol 	    } else {
9082c9bd703SFrançois Revol 		/* R */
9092c9bd703SFrançois Revol 		if ( i < (WIDTH*(HEIGHT-1)) && ((i % WIDTH) < (WIDTH-1)) ) {
9102c9bd703SFrançois Revol 		    *scanpt++ = *rawpt;					/* R */
9112c9bd703SFrançois Revol 		    *scanpt++ = (*(rawpt-1)+*(rawpt+1)+
9122c9bd703SFrançois Revol 				 *(rawpt-WIDTH)+*(rawpt+WIDTH))/4;	/* G */
9132c9bd703SFrançois Revol 		    *scanpt++ = (*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+
9142c9bd703SFrançois Revol 				 *(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4;	/* B */
9152c9bd703SFrançois Revol 		} else {
9162c9bd703SFrançois Revol 		    /* bottom line or right column */
9172c9bd703SFrançois Revol 		    *scanpt++ = *rawpt;				/* R */
9182c9bd703SFrançois Revol 		    *scanpt++ = (*(rawpt-1)+*(rawpt-WIDTH))/2;	/* G */
9192c9bd703SFrançois Revol 		    *scanpt++ = *(rawpt-WIDTH-1);		/* B */
9202c9bd703SFrançois Revol 		}
9212c9bd703SFrançois Revol 	    }
9222c9bd703SFrançois Revol 	}
9232c9bd703SFrançois Revol 	rawpt++;
9242c9bd703SFrançois Revol     }
9252c9bd703SFrançois Revol 
9262c9bd703SFrançois Revol }
9272c9bd703SFrançois Revol 
9282c9bd703SFrançois Revol /* modified bayer2rgb24 to output rgb-32 little endian (B_RGB32)
9292c9bd703SFrançois Revol  * François Revol
9302c9bd703SFrançois Revol  */
9312c9bd703SFrançois Revol 
bayer2rgb32le(unsigned char * dst,unsigned char * src,long int WIDTH,long int HEIGHT)9322c9bd703SFrançois Revol void bayer2rgb32le(unsigned char *dst, unsigned char *src, long int WIDTH, long int HEIGHT)
9332c9bd703SFrançois Revol {
9342c9bd703SFrançois Revol     long int i;
9352c9bd703SFrançois Revol     unsigned char *rawpt, *scanpt;
9362c9bd703SFrançois Revol     long int size;
9372c9bd703SFrançois Revol 
9382c9bd703SFrançois Revol     rawpt = src;
9392c9bd703SFrançois Revol     scanpt = dst;
9402c9bd703SFrançois Revol     size = WIDTH*HEIGHT;
9412c9bd703SFrançois Revol 
9422c9bd703SFrançois Revol     for ( i = 0; i < size; i++ ) {
9432c9bd703SFrançois Revol 	if ( (i/WIDTH) % 2 == 0 ) {
9442c9bd703SFrançois Revol 	    if ( (i % 2) == 0 ) {
9452c9bd703SFrançois Revol 		/* B */
9462c9bd703SFrançois Revol 		if ( (i > WIDTH) && ((i % WIDTH) > 0) ) {
9472c9bd703SFrançois Revol 		    *scanpt++ = *rawpt;					/* B */
9482c9bd703SFrançois Revol 		    *scanpt++ = (*(rawpt-1)+*(rawpt+1)+
9492c9bd703SFrançois Revol 				 *(rawpt+WIDTH)+*(rawpt-WIDTH))/4;	/* G */
9502c9bd703SFrançois Revol 		    *scanpt++ = (*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+
9512c9bd703SFrançois Revol 				 *(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4;	/* R */
9522c9bd703SFrançois Revol 		} else {
9532c9bd703SFrançois Revol 		    /* first line or left column */
9542c9bd703SFrançois Revol 		    *scanpt++ = *rawpt;				/* B */
9552c9bd703SFrançois Revol 		    *scanpt++ = (*(rawpt+1)+*(rawpt+WIDTH))/2;	/* G */
9562c9bd703SFrançois Revol 		    *scanpt++ = *(rawpt+WIDTH+1);		/* R */
9572c9bd703SFrançois Revol 		}
9582c9bd703SFrançois Revol 	    } else {
9592c9bd703SFrançois Revol 		/* (B)G */
9602c9bd703SFrançois Revol 		if ( (i > WIDTH) && ((i % WIDTH) < (WIDTH-1)) ) {
9612c9bd703SFrançois Revol 		    *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2;		/* B */
9622c9bd703SFrançois Revol 		    *scanpt++ = *rawpt;					/* G */
9632c9bd703SFrançois Revol 		    *scanpt++ = (*(rawpt+WIDTH)+*(rawpt-WIDTH))/2;	/* R */
9642c9bd703SFrançois Revol 		} else {
9652c9bd703SFrançois Revol 		    /* first line or right column */
9662c9bd703SFrançois Revol 		    *scanpt++ = *(rawpt-1);	/* B */
9672c9bd703SFrançois Revol 		    *scanpt++ = *rawpt;		/* G */
9682c9bd703SFrançois Revol 		    *scanpt++ = *(rawpt+WIDTH);	/* R */
9692c9bd703SFrançois Revol 		}
9702c9bd703SFrançois Revol 	    }
9712c9bd703SFrançois Revol 	} else {
9722c9bd703SFrançois Revol 	    if ( (i % 2) == 0 ) {
9732c9bd703SFrançois Revol 		/* G(R) */
9742c9bd703SFrançois Revol 		if ( (i < (WIDTH*(HEIGHT-1))) && ((i % WIDTH) > 0) ) {
9752c9bd703SFrançois Revol 		    *scanpt++ = (*(rawpt+WIDTH)+*(rawpt-WIDTH))/2;	/* B */
9762c9bd703SFrançois Revol 		    *scanpt++ = *rawpt;					/* G */
9772c9bd703SFrançois Revol 		    *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2;		/* R */
9782c9bd703SFrançois Revol 		} else {
9792c9bd703SFrançois Revol 		    /* bottom line or left column */
9802c9bd703SFrançois Revol 		    *scanpt++ = *(rawpt-WIDTH);		/* B */
9812c9bd703SFrançois Revol 		    *scanpt++ = *rawpt;			/* G */
9822c9bd703SFrançois Revol 		    *scanpt++ = *(rawpt+1);		/* R */
9832c9bd703SFrançois Revol 		}
9842c9bd703SFrançois Revol 	    } else {
9852c9bd703SFrançois Revol 		/* R */
9862c9bd703SFrançois Revol 		if ( i < (WIDTH*(HEIGHT-1)) && ((i % WIDTH) < (WIDTH-1)) ) {
9872c9bd703SFrançois Revol 		    *scanpt++ = (*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+
9882c9bd703SFrançois Revol 				 *(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4;	/* B */
9892c9bd703SFrançois Revol 		    *scanpt++ = (*(rawpt-1)+*(rawpt+1)+
9902c9bd703SFrançois Revol 				 *(rawpt-WIDTH)+*(rawpt+WIDTH))/4;	/* G */
9912c9bd703SFrançois Revol 		    *scanpt++ = *rawpt;					/* R */
9922c9bd703SFrançois Revol 		} else {
9932c9bd703SFrançois Revol 		    /* bottom line or right column */
9942c9bd703SFrançois Revol 		    *scanpt++ = *(rawpt-WIDTH-1);		/* B */
9952c9bd703SFrançois Revol 		    *scanpt++ = (*(rawpt-1)+*(rawpt-WIDTH))/2;	/* G */
9962c9bd703SFrançois Revol 		    *scanpt++ = *rawpt;				/* R */
9972c9bd703SFrançois Revol 		}
9982c9bd703SFrançois Revol 	    }
9992c9bd703SFrançois Revol 	}
10002c9bd703SFrançois Revol 	rawpt++;
10012c9bd703SFrançois Revol 	scanpt++;
10022c9bd703SFrançois Revol     }
10032c9bd703SFrançois Revol 
10042c9bd703SFrançois Revol }
1005