diff --git a/melonDS.cbp b/melonDS.cbp
index cc5357b9..be1f30b7 100644
--- a/melonDS.cbp
+++ b/melonDS.cbp
@@ -106,6 +106,8 @@
 		<Unit filename="src/DSiCrypto.h" />
 		<Unit filename="src/DSi_AES.cpp" />
 		<Unit filename="src/DSi_AES.h" />
+		<Unit filename="src/DSi_Camera.cpp" />
+		<Unit filename="src/DSi_Camera.h" />
 		<Unit filename="src/DSi_I2C.cpp" />
 		<Unit filename="src/DSi_I2C.h" />
 		<Unit filename="src/DSi_NDMA.cpp" />
diff --git a/src/DSi_Camera.cpp b/src/DSi_Camera.cpp
new file mode 100644
index 00000000..66d08cb4
--- /dev/null
+++ b/src/DSi_Camera.cpp
@@ -0,0 +1,143 @@
+/*
+    Copyright 2016-2019 Arisotura
+
+    This file is part of melonDS.
+
+    melonDS is free software: you can redistribute it and/or modify it under
+    the terms of the GNU General Public License as published by the Free
+    Software Foundation, either version 3 of the License, or (at your option)
+    any later version.
+
+    melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
+    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+    FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with melonDS. If not, see http://www.gnu.org/licenses/.
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include "DSi_Camera.h"
+
+
+DSi_Camera* DSi_Camera0; // 78 / facing outside
+DSi_Camera* DSi_Camera1; // 7A / selfie cam
+
+
+bool DSi_Camera::Init()
+{
+    DSi_Camera0 = new DSi_Camera(0);
+    DSi_Camera1 = new DSi_Camera(1);
+
+    return true;
+}
+
+void DSi_Camera::DeInit()
+{
+    delete DSi_Camera0;
+    delete DSi_Camera1;
+}
+
+void DSi_Camera::Reset()
+{
+    DSi_Camera0->ResetCam();
+    DSi_Camera1->ResetCam();
+}
+
+
+DSi_Camera::DSi_Camera(u32 num)
+{
+    Num = num;
+}
+
+DSi_Camera::~DSi_Camera()
+{
+    //
+}
+
+void DSi_Camera::ResetCam()
+{
+    DataPos = 0;
+    RegAddr = 0;
+    RegData = 0;
+}
+
+
+void DSi_Camera::Start()
+{
+}
+
+u8 DSi_Camera::Read(bool last)
+{
+    u8 ret;
+
+    if (DataPos < 2)
+    {
+        printf("DSi_Camera: WHAT??\n");
+        ret = 0;
+    }
+    else
+    {
+        if (DataPos & 0x1)
+        {
+            ret = RegData & 0xFF;
+            RegAddr += 2; // checkme
+        }
+        else
+        {
+            RegData = ReadReg(RegAddr);
+            ret = RegData >> 8;
+        }
+    }
+
+    if (last) DataPos = 0;
+    else      DataPos++;
+
+    return ret;
+}
+
+void DSi_Camera::Write(u8 val, bool last)
+{
+    if (DataPos < 2)
+    {
+        if (DataPos == 0)
+            RegAddr = val << 8;
+        else
+            RegAddr |= val;
+
+        if (RegAddr & 0x1) printf("DSi_Camera: !! UNALIGNED REG ADDRESS %04X\n", RegAddr);
+    }
+    else
+    {
+        if (DataPos & 0x1)
+        {
+            RegData |= val;
+            WriteReg(RegAddr, RegData);
+            RegAddr += 2; // checkme
+        }
+        else
+        {
+            RegData = val << 8;
+        }
+    }
+
+    if (last) DataPos = 0;
+    else      DataPos++;
+}
+
+u16 DSi_Camera::ReadReg(u16 addr)
+{
+    switch (addr)
+    {
+    case 0x301A: return 0x0002; // HAX
+    }
+
+    printf("DSi_Camera%d: unknown read %04X\n", Num, addr);
+    return 0;
+}
+
+void DSi_Camera::WriteReg(u16 addr, u16 val)
+{
+    printf("DSi_Camera%d: unknown write %04X %04X\n", Num, addr, val);
+}
diff --git a/src/DSi_Camera.h b/src/DSi_Camera.h
new file mode 100644
index 00000000..eba35cb8
--- /dev/null
+++ b/src/DSi_Camera.h
@@ -0,0 +1,55 @@
+/*
+    Copyright 2016-2019 Arisotura
+
+    This file is part of melonDS.
+
+    melonDS is free software: you can redistribute it and/or modify it under
+    the terms of the GNU General Public License as published by the Free
+    Software Foundation, either version 3 of the License, or (at your option)
+    any later version.
+
+    melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
+    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+    FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with melonDS. If not, see http://www.gnu.org/licenses/.
+*/
+
+#ifndef DSI_CAMERA_H
+#define DSI_CAMERA_H
+
+#include "types.h"
+
+class DSi_Camera
+{
+public:
+    static bool Init();
+    static void DeInit();
+    static void Reset();
+
+    DSi_Camera(u32 num);
+    ~DSi_Camera();
+
+    void ResetCam();
+
+    void Start();
+    u8 Read(bool last);
+    void Write(u8 val, bool last);
+
+private:
+    u32 Num;
+
+    u32 DataPos;
+    u32 RegAddr;
+    u16 RegData;
+
+    u16 ReadReg(u16 addr);
+    void WriteReg(u16 addr, u16 val);
+};
+
+
+extern DSi_Camera* DSi_Camera0;
+extern DSi_Camera* DSi_Camera1;
+
+#endif // DSI_CAMERA_H
diff --git a/src/DSi_I2C.cpp b/src/DSi_I2C.cpp
index e88858b2..907d0eff 100644
--- a/src/DSi_I2C.cpp
+++ b/src/DSi_I2C.cpp
@@ -20,6 +20,7 @@
 #include <string.h>
 #include "DSi.h"
 #include "DSi_I2C.h"
+#include "DSi_Camera.h"
 
 
 namespace DSi_BPTWL
@@ -131,6 +132,7 @@ u32 Device;
 bool Init()
 {
     if (!DSi_BPTWL::Init()) return false;
+    if (!DSi_Camera::Init()) return false;
 
     return true;
 }
@@ -138,6 +140,7 @@ bool Init()
 void DeInit()
 {
     DSi_BPTWL::DeInit();
+    DSi_Camera::DeInit();
 }
 
 void Reset()
@@ -148,6 +151,7 @@ void Reset()
     Device = -1;
 
     DSi_BPTWL::Reset();
+    DSi_Camera::Reset();
 }
 
 void WriteCnt(u8 val)
@@ -171,37 +175,55 @@ void WriteCnt(u8 val)
             switch (Device)
             {
             case 0x4A: Data = DSi_BPTWL::Read(islast); break;
-            default: Data = 0; break;
+            case 0x78: Data = DSi_Camera0->Read(islast); break;
+            case 0x7A: Data = DSi_Camera1->Read(islast); break;
+            default:
+                printf("I2C: read on unknown device %02X, cnt=%02X, data=%02X, last=%d\n", Device, val, 0, islast);
+                Data = 0;
+                break;
             }
 
-            //printf("I2C read, device=%02X, cnt=%02X, data=%02X, last=%d\n", Device, val, Data, islast);
+            printf("I2C read, device=%02X, cnt=%02X, data=%02X, last=%d\n", Device, val, Data, islast);
         }
         else
         {
             // write
             val &= 0xE7;
+            bool ack = true;
 
             if (val & (1<<1))
             {
                 Device = Data & 0xFE;
-                //printf("I2C: %s start, device=%02X\n", (Data&0x01)?"read":"write", Device);
+                printf("I2C: %s start, device=%02X\n", (Data&0x01)?"read":"write", Device);
 
                 switch (Device)
                 {
                 case 0x4A: DSi_BPTWL::Start(); break;
+                case 0x78: DSi_Camera0->Start(); break;
+                case 0x7A: DSi_Camera1->Start(); break;
+                default:
+                    printf("I2C: %s start on unknown device %02X\n", (Data&0x01)?"read":"write", Device);
+                    ack = false;
+                    break;
                 }
             }
             else
             {
-                //printf("I2C write, device=%02X, cnt=%02X, data=%02X, last=%d\n", Device, val, Data, islast);
+                printf("I2C write, device=%02X, cnt=%02X, data=%02X, last=%d\n", Device, val, Data, islast);
 
                 switch (Device)
                 {
                 case 0x4A: DSi_BPTWL::Write(Data, islast); break;
+                case 0x78: DSi_Camera0->Write(Data, islast); break;
+                case 0x7A: DSi_Camera1->Write(Data, islast); break;
+                default:
+                    printf("I2C: write on unknown device %02X, cnt=%02X, data=%02X, last=%d\n", Device, val, Data, islast);
+                    ack = false;
+                    break;
                 }
             }
 
-            val |= (1<<4);
+            if (ack) val |= (1<<4);
         }
 
         val &= 0x7F;