<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Gohanks' Retro Corner]]></title><description><![CDATA[My small corner of the retro computing world. Projects, articles, news and dev blog.]]></description><link>https://gohanks.com/</link><image><url>https://gohanks.com/favicon.png</url><title>Gohanks&apos; Retro Corner</title><link>https://gohanks.com/</link></image><generator>Ghost 4.48</generator><lastBuildDate>Tue, 01 Sep 2026 04:31:53 GMT</lastBuildDate><atom:link href="https://gohanks.com/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[MCP authorization, with Authentik as the identity provider]]></title><description><![CDATA[<p>If you&#x2019;re wiring an MCP server up to Authentik and stuck on how a client is supposed to get a token, this is for you. We hit the same wall, and the short version is: <strong><strong>Authentik cannot be the OAuth authorization server for your MCP clients, and no</strong></strong></p>]]></description><link>https://gohanks.com/mcp-authorization-with-authentik-as-the-identity-provider/</link><guid isPermaLink="false">6a6a51256d8a970001fa76f6</guid><dc:creator><![CDATA[Gohanks]]></dc:creator><pubDate>Wed, 29 Jul 2026 19:15:45 GMT</pubDate><content:encoded><![CDATA[<p>If you&#x2019;re wiring an MCP server up to Authentik and stuck on how a client is supposed to get a token, this is for you. We hit the same wall, and the short version is: <strong><strong>Authentik cannot be the OAuth authorization server for your MCP clients, and no amount of configuration fixes that.</strong></strong> It has to be someone else &#x2014; plausibly your own resource server. Here&#x2019;s how we got there, including the wrong turn we took first.</p><h2 id="the-problem-precisely"><strong><strong>The problem, precisely</strong></strong></h2><p>MCP&#x2019;s authorization spec builds on OAuth 2.1. Your resource server (the thing serving <code>POST /mcp</code>) points clients at an authorization server, and the client gets a token from it before it&#x2019;s allowed to call a tool. Nothing unusual so far &#x2014; except MCP clients are typically dynamic. Claude Code doesn&#x2019;t ship with a pre-registered <code>client_id</code> for your server; it expects to either:</p><ul><li>register itself on the fly via <strong><strong>RFC 7591 Dynamic Client Registration</strong></strong> (<code>POST /oauth/register</code>), or</li><li>present a <strong><strong>Client ID Metadata Document</strong></strong> (CIMD) &#x2014; an <code>client_id</code> that is itself an <code>https://</code> URL the authorization server fetches to learn who&#x2019;s asking.</li></ul><p>Authentik supports neither. There&#x2019;s no <code>registration_endpoint</code> in its discovery document, <code>POST /register</code> doesn&#x2019;t exist, and CIMD support isn&#x2019;t there either. This isn&#x2019;t a config flag you&#x2019;re missing &#x2014; <a href="https://github.com/goauthentik/authentik/issues/8751">goauthentik#8751</a> has been open since February 2024, milestoned, unshipped. Every OAuth client Authentik can talk to has to be created by hand in its admin UI.</p><p>That&#x2019;s fine for your web app&#x2019;s login &#x2014; you register <code>assistant-web</code> once and move on. It&#x2019;s fatal for MCP, because you don&#x2019;t control the client. Claude Code tries dynamic registration, finds nothing, and gives up with <em>&#x201C;Incompatible auth server: does not support dynamic client registration.&#x201D;</em> There&#x2019;s a <code>claude mcp add --client-id</code> escape hatch for pre-registered clients, but it&#x2019;s a dead end too &#x2014; <a href="https://github.com/anthropics/claude-code/issues/38102">claude-code#38102</a>, closed as not planned, reports the flag being silently ignored. And even if it worked, &#x201C;manually register a client per person who wants to connect&#x201D; is the exact toil DCR exists to avoid.</p><p>So: pointing MCP clients at Authentik for a token is a dead end. Something else has to be the authorization server.</p><h2 id="the-shortcut-that-looks-free-and-isn%E2%80%99t"><strong><strong>The shortcut that looks free, and isn&#x2019;t</strong></strong></h2><p>Before building a real authorization server, we considered the cheap version: a thin shim that answers discovery and registration requests itself, but hands off the actual <code>authorization_endpoint</code> and <code>token_endpoint</code> to Authentik. Every client that registers gets mapped onto one pre-provisioned Authentik client under the hood. No new state machine, no token storage, just a translation layer.</p><p>It doesn&#x2019;t survive contact with a conformant client, for a specific and checkable reason. The MCP authorization spec has clients record the <code>issuer</code> from the metadata document they validated, and compare it against the <strong><strong>RFC 9207</strong></strong> <code>iss</code> parameter attached to the callback. If your metadata document advertises your own issuer, but Authentik is the one that actually answers the authorization request and stamps the callback, the two <code>iss</code> values never match. Every conformant client rejects the response as a possible mix-up attack; a client that doesn&#x2019;t check <code>iss</code> accepts it, silently, which is worse.</p><p>Fixing that would mean Authentik answering <em>as</em> your issuer &#x2014; which it can&#x2019;t &#x2014; or forwarding requests through in a way that makes the shim not &#x201C;thin&#x201D; anymore: a redirect-URI allowlist covering both <code>claude.ai</code> and arbitrary loopback ports, a property mapping to fake an audience per client, and one shared <code>client_id</code> standing in for every distinct caller. At that point you&#x2019;ve built an authorization server with extra steps and none of the guarantees.</p><h2 id="the-actual-fix-be-your-own-authorization-server"><strong><strong>The actual fix: be your own authorization server</strong></strong></h2><p>The resource server &#x2014; the thing serving <code>/mcp</code> &#x2014; becomes the OAuth 2.1 authorization server for its own resource. Authentik keeps doing exactly the one thing it&#x2019;s good at and nothing more: authenticating the human. It gains no new client, no new provider, no new configuration. If you already run an OIDC backend-for-frontend in front of Authentik for your web login, this slots in beside it rather than replacing anything.</p><p>Concretely, that means your API now serves:</p><ul><li><code>GET /.well-known/oauth-authorization-server</code> (RFC 8414 metadata)</li><li><code>GET /.well-known/oauth-protected-resource</code> (RFC 9728, unauthenticated by design &#x2014; it&#x2019;s how a client with no token yet finds out where to go)</li><li><code>POST /oauth/register</code> (RFC 7591 DCR) and CIMD support</li><li><code>GET /oauth/authorize</code>, <code>POST /oauth/token</code>, <code>POST /oauth/revoke</code> (RFC 7009)</li><li>a consent screen, somewhere your frontend owns</li></ul><p>The handoff to Authentik happens at exactly one point: <code>GET /oauth/authorize</code> with no existing session redirects into your ordinary login flow &#x2014; Authentik does its OIDC dance, your callback handler does its usual thing &#x2014; and then resumes the authorization request it was in the middle of. Authentik never hears the word &#x201C;MCP.&#x201D; As far as it&#x2019;s concerned, a human just logged in.</p><p>One wrinkle worth knowing before you hit it: if your callback handler regenerates the session id after login (the standard defence against session fixation &#x2014; and you should be doing this already), anything you stashed in the session before the login hop is gone when you come back. That&#x2019;s why the &#x201C;resume&#x201D; step can&#x2019;t rely on session state. Persist the in-flight authorization request as a <strong><strong>row</strong></strong> &#x2014; an id round-trips through the login detour just fine even though the session object underneath it gets replaced.</p><h2 id="the-pieces-that-actually-matter"><strong><strong>The pieces that actually matter</strong></strong></h2><p>You don&#x2019;t need to reimplement all of OAuth from scratch to get this right, but a few decisions are load-bearing and worth making deliberately rather than defaulting into:</p><p><strong><strong>Public clients only, PKCE mandatory, no client secret.</strong></strong> Every MCP client is either a loopback native app or a browser app; neither can keep a secret, so don&#x2019;t pretend otherwise by adding a <code>client_secret</code> column you&#x2019;ll never populate safely. OAuth 2.1 makes PKCE (S256) mandatory for exactly this reason &#x2014; it&#x2019;s your actual protection, not the secret you don&#x2019;t have.</p><p><strong><strong>Opaque tokens, hashed, not JWTs.</strong></strong> The usual case for signed JWTs is avoiding a database round-trip per request. That case evaporates here: you already need one lookup to turn a token&#x2019;s subject into a local user, so with your own tokens that same lookup <em>is</em> the verification. What you get back for giving up the &#x201C;stateless&#x201D; property is revocation that actually means something &#x2014; disconnecting a client is an <code>UPDATE</code>, not a denylist &#x2014; and no JWKS endpoint to stand up, rotate, or back up. Store tokens as SHA-256 digests, never plaintext, so a database dump isn&#x2019;t a bag of live credentials.</p><p><strong><strong>RFC 8707 <code>resource</code> bound into the grant, not just checked once.</strong></strong> Validate it on the authorization request, freeze it into the code, bind it into the grant. This is what makes &#x201C;this token was minted for <em>this</em> MCP server&#x201D; a fact your resource server can check locally, rather than something it has to trust the identity provider got right &#x2014; which matters a lot once you&#x2019;re the one issuing the token in the first place.</p><p><strong><strong>A real consent screen, because DCR is unauthenticated by specification.</strong></strong> Nothing stops an attacker from registering a client that looks legitimate and points its redirect URI at their own server. The thing that separates a client your user actually wants connected from one an attacker created is a human looking at a screen that says <em>this client, this destination</em> and clicking allow. Don&#x2019;t skip this because registration already &#x201C;succeeded&#x201D; &#x2014; registration creating a row and a human approving it are different events, and only the second one should unlock a token. Two things are worth <em>not</em> rendering on that screen: a client-supplied <code>logo_uri</code> (an unauthenticated registrant can point it at anything, including content that makes an attacker&#x2019;s client look like a trusted one), and any of <code>state</code>, <code>code_challenge</code>, or <code>resource</code> &#x2014; the screen has no use for them, and a value that never reaches the browser can&#x2019;t be tampered with there.</p><p><strong><strong>Loopback redirect-URI matching has to ignore the port, but only there.</strong></strong> CLI-style MCP clients bind an ephemeral loopback port every run, and a strict string match will accept exactly one session and reject every one after. OAuth 2.1 &#xA7;8.4.2 and RFC 8252 &#xA7;7.3 carve out <code>127.0.0.1</code>, <code>localhost</code>, and <code>[::1]</code> specifically for this. Scope the exemption tightly &#x2014; <code>http</code> only, those hosts only, and only the port &#x2014; because <code>http://127.0.0.1.evil.example/callback</code> is not loopback, and an <code>https</code> redirect never gets this relaxation at all.</p><p><strong><strong>Two situations should revoke, not just refuse.</strong></strong> A replayed authorization code and a reused (already-rotated) refresh token are both ambiguous: maybe your own client retried after losing a response, maybe someone has a stolen copy. OAuth 2.1 &#xA7;4.1.3 tells you to assume the worst &#x2014; kill the whole grant, not just the one bad request. Refusing the replay while leaving the original tokens alive means an attacker who won the race still has something that works.</p><h2 id="what-we-didn%E2%80%99t-build-on-purpose"><strong><strong>What we didn&#x2019;t build, on purpose</strong></strong></h2><p>Not every gap is worth closing immediately, and it&#x2019;s worth being explicit about which ones you&#x2019;re choosing to leave open rather than discovering it later:</p><ul><li><strong><strong>Granular scopes.</strong></strong> One scope is enough when authorization is identity-based &#x2014; a valid token says who you are, and your existing ownership/visibility rules decide what that allows. Scope-gated tools are future work, not a blocker.</li><li><strong><strong><code>client_credentials</code>.</strong></strong> There&#x2019;s no &#x201C;client&#x201D; here without a human behind it; every flow is a person authorizing an app on their own behalf.</li><li><strong><strong>RFC 7592 client management.</strong></strong> Optional, and one more near-unauthenticated surface you&#x2019;d have to defend.</li><li><strong><strong>Forced re-authentication on every <code>/oauth/authorize</code>.</strong></strong> Requiring a fresh login every time someone connects a client trades a small security increment for a real amount of friction, and the predictable response to friction is people choosing longer-lived tokens instead &#x2014; which is worse. Per-client consent is what actually defends against a malicious client; it doesn&#x2019;t need session age to do that job.</li></ul><h2 id="a-checklist-for-your-own-authentik-instance"><strong><strong>A checklist for your own Authentik instance</strong></strong></h2><p>If you&#x2019;re reproducing this shape:</p><ol><li>Leave Authentik alone. You register <strong><strong>one</strong></strong> redirect URI there &#x2014; your app&#x2019;s normal OIDC callback &#x2014; and nothing MCP-specific ever gets configured at the IdP. If you find yourself adding an MCP-flavoured client, property mapping, or scope to Authentik, you&#x2019;ve gone down the shim path above; back out.</li><li>Your resource server&#x2019;s canonical URI does double duty: it&#x2019;s the value clients pass as <code>resource</code> (RFC 8707), it&#x2019;s what you bind into every grant, and its origin is your new authorization server&#x2019;s issuer identifier. Derive the issuer from that URI rather than configuring it separately &#x2014; one source for both, so they can&#x2019;t drift apart.</li><li>Verify the two discovery documents first, before you try a real client: <code>/.well-known/oauth-protected-resource</code> and <code>/.well-known/oauth-authorization-server</code>. A 404 on either, in production, usually means a reverse proxy isn&#x2019;t routing those paths to your API &#x2014; it&#x2019;s indistinguishable from &#x201C;no authorization server exists&#x201D; to the client, so it&#x2019;s the first thing to rule out.</li><li>Call <code>/mcp</code> with no token and check the <code>401</code>. The <code>WWW-Authenticate</code> header should name the protected-resource metadata document and a scope &#x2014; that header <em>is</em> the discovery mechanism, and a client that can&#x2019;t find it never gets any further.</li><li>Only then try a real client end to end: register (or present a CIMD), authorize, land on your consent screen, approve, and confirm the redirect carries a code your token endpoint accepts. If step 4 works but this doesn&#x2019;t, the break is almost always in redirect-URI matching or PKCE verification, not in Authentik.</li></ol><p>Authentik is still doing real work in this design &#x2014; it&#x2019;s the thing that knows who your users are, and nothing above changes that. It just isn&#x2019;t, and structurally can&#x2019;t be, the party that decides what an MCP client is allowed to do on a user&#x2019;s behalf. Once that split clicks, the rest is a fairly ordinary OAuth 2.1 authorization server, sized to the one resource it exists to protect.</p>]]></content:encoded></item><item><title><![CDATA[Fixing HP Network Scanner Issues on Ubuntu (AirScan vs HPLIP Stability Problem)]]></title><description><![CDATA[<h2 id="introduction">Introduction</h2><p>If you are using an HP network scanner on Ubuntu and experiencing unstable behavior during scanning (especially multi-page scans failing partway through), you are not alone.</p><p>A common issue with HP LaserJet MFP devices on Linux is that scanning appears to work initially but then fails after several pages.</p>]]></description><link>https://gohanks.com/fixing-hp-network-scanner-issues-on-ubuntu-airscan-vs-hplip-stability-problem/</link><guid isPermaLink="false">69de8f49b31ef4000153599c</guid><dc:creator><![CDATA[Gohanks]]></dc:creator><pubDate>Tue, 14 Apr 2026 19:08:24 GMT</pubDate><content:encoded><![CDATA[<h2 id="introduction">Introduction</h2><p>If you are using an HP network scanner on Ubuntu and experiencing unstable behavior during scanning (especially multi-page scans failing partway through), you are not alone.</p><p>A common issue with HP LaserJet MFP devices on Linux is that scanning appears to work initially but then fails after several pages. The scanner physically runs, but no output is produced in the software, and the system often only recovers after a reboot.</p><p>This article explains the real cause of the problem and how to permanently fix it by switching from the legacy HP driver stack to AirScan.</p><hr><h2 id="symptoms-of-the-problem">Symptoms of the Problem</h2><p>The issue typically looks like this:</p><ul><li>Scanner is correctly detected in Ubuntu</li><li>Single-page scans work normally</li><li>Multi-page scans fail after a few successful pages (often around 8&#x2013;10)</li><li>The scanner physically scans the document, but no image appears in the application</li><li>Restarting the scanning application does not help</li><li>Only a full system reboot temporarily restores functionality</li></ul><p>At first glance, this looks like a network or hardware issue. In reality, it is caused by the scanning backend configuration.</p><hr><h2 id="understanding-the-cause">Understanding the Cause</h2><p>On Ubuntu, HP scanners can be accessed through multiple backends at the same time:</p><ul><li>AirScan (modern eSCL-based network scanning)</li><li>ESCL (raw eSCL interface)</li><li>HPLIP / hpaio (legacy HP scanning backend)</li></ul><p>The key issue is that the system may default to using the legacy HPLIP backend even when a modern AirScan interface is available.</p><h3 id="the-real-problem-hplip-instability">The real problem: HPLIP instability</h3><p>The HP Linux Imaging and Printing system (HPLIP) includes a scanning backend called <code>hp</code> / <code>hpaio</code>. While historically important, it is increasingly problematic for modern network-connected HP devices.</p><p>In this case, the issues observed were caused by the HPLIP backend:</p><ul><li>It maintains internal session state across scans</li><li>It can fail after repeated scan jobs</li><li>It may corrupt or lose the image data stream</li><li>It can leave the scanner backend in a broken state until system restart</li></ul><p>This explains the key symptom: the scan physically completes, but no data is returned to the system.</p><hr><h2 id="why-airscan-works">Why AirScan Works</h2><p>AirScan uses the modern eSCL protocol (used by most newer HP network printers). Unlike HPLIP, it works in a much simpler and more reliable way:</p><ul><li>Each scan is stateless</li><li>Communication is handled over standard HTTP</li><li>No persistent session state is required</li><li>No vendor-specific backend logic is involved</li></ul><p>Because of this, AirScan avoids the instability seen in the HPLIP stack.</p><hr><h2 id="how-the-issue-was-diagnosed">How the Issue Was Diagnosed</h2><p>The first step was to identify which scanner backends were active:</p><!--kg-card-begin: markdown--><pre><code class="language-bash">scanimage -L</code></pre>
<!--kg-card-end: markdown--><p>This showed multiple available backends, including:</p><ul><li>airscan (eSCL-based)</li><li>escl (raw interface)</li><li>hpaio (HPLIP backend)</li></ul><p>To isolate the issue, each backend was tested directly.</p><h3 id="airscan-test">AirScan test</h3><!--kg-card-begin: markdown--><pre><code class="language-bash">scanimage -d airscan:e0:DEVICE_NAME --format=png &gt; test.png
</code></pre>
<!--kg-card-end: markdown--><p>Result: stable and reliable scanning.</p><h3 id="hplip-test">HPLIP test</h3><!--kg-card-begin: markdown--><pre><code class="language-bash">scanimage -d hpaio:... --format=png &gt; test.png
</code></pre>
<!--kg-card-end: markdown--><p>Result: immediate failure or I/O errors.</p><p>This confirmed that the issue was not related to the scanner hardware or network, but specifically to the HPLIP backend.</p><hr><h2 id="the-fix">The Fix</h2><p>The solution was to remove the legacy HP scanning backend and rely exclusively on AirScan.</p><h3 id="step-1-remove-hplip-scanning-components">Step 1: Remove HPLIP scanning components</h3><!--kg-card-begin: markdown--><pre><code class="language-bash">sudo apt remove hplip libsane-hpaio
</code></pre>
<!--kg-card-end: markdown--><h3 id="step-2-verify-available-scanners">Step 2: Verify available scanners</h3><!--kg-card-begin: markdown--><pre><code class="language-bash">scanimage -L</code></pre>
<!--kg-card-end: markdown--><p>After removal, only AirScan-based devices should remain.</p><h3 id="step-3-confirm-stable-operation">Step 3: Confirm stable operation</h3><!--kg-card-begin: markdown--><pre><code class="language-bash">scanimage -d airscan:e0:DEVICE_NAME --format=png &gt; test.png
</code></pre>
<!--kg-card-end: markdown--><p>At this point, scanning becomes stable even for multi-page documents.</p><hr><h2 id="results-after-fix">Results After Fix</h2><p>Once the HPLIP backend was removed:</p><ul><li>Multi-page scanning became stable</li><li>No more silent scan failures</li><li>No need to reboot the system</li><li>Ubuntu scanning applications worked normally again</li><li>Only AirScan was used as the scanning backend</li></ul><hr><h2 id="key-takeaways">Key Takeaways</h2><ul><li>Seeing multiple scanner backends in Ubuntu is normal</li><li>The presence of HPLIP does not mean it is the best option</li><li>Modern HP network scanners should use AirScan whenever available</li><li>HPLIP scanning backend can cause instability on repeated or multi-page scans</li><li>Removing legacy backends can significantly improve reliability</li></ul><hr><h2 id="conclusion">Conclusion</h2><p>This issue was not caused by Ubuntu, the scanner hardware, or the network connection. The root cause was the interaction between a modern HP network scanner and a legacy scanning backend (HPLIP) that is no longer well suited for this type of device.</p><p>Switching fully to AirScan resolved the instability completely and restored reliable scanning behavior.</p>]]></content:encoded></item><item><title><![CDATA[Clever reset solution and more]]></title><description><![CDATA[<p>Hello! Since this blog was created a few months ago it&apos;s been completely void of any content. To mitigate this I thought I&apos;ll kick things off with rehashing one of my old articles, originally written for Hot-Style #7, a polish C64 diskmag, which I recommend to</p>]]></description><link>https://gohanks.com/clever-reset-solution-and-more/</link><guid isPermaLink="false">6526eeaba9ebdc0001c503c9</guid><category><![CDATA[Commodore]]></category><dc:creator><![CDATA[Gohanks]]></dc:creator><pubDate>Wed, 11 Oct 2023 20:34:21 GMT</pubDate><content:encoded><![CDATA[<p>Hello! Since this blog was created a few months ago it&apos;s been completely void of any content. To mitigate this I thought I&apos;ll kick things off with rehashing one of my old articles, originally written for Hot-Style #7, a polish C64 diskmag, which I recommend to check for yourself: <a href="https://csdb.dk/release/?id=206132">https://csdb.dk/release/?id=206132</a></p><p>Anyways, enjoy the first article, more to follow soon :) (or in a couple of months, we&apos;ll see ;) )</p><p></p><p>The C64 users always had an inconvenient little problem with the machine &#x2013; lack of convenient reset button. They devised a lot of different minor and major modifications to solve that problem. There&#x2019;s a lot to say about all of them, but one has speciffically caught my attention and I decided to apply it in my own modded C64C.</p><p>I&#x2019;m talking about a small project, that I&#x2019;ve found while browsing through C64 websites. It&#x2019;s author cleverly used &#xA0;a cheap and highly available Atmega microcontroler circuit &#x2013; Arduino Pro Mini.</p><p>Original article can be located here: <a href="http://www.breadbox64.com/blog/switchless-reset-mod/">http://www.breadbox64.com/blog/switchless-reset-mod/</a>, but I&#x2019;ll describe a version that I&#x2019;ve updated with a few minor tweaks.</p><p>The concept is simple, we upload a program into the circuit, which based on input signals (in this case the RESTORE button press) controls the signals sent to Commodore`s motherboard resulting in warm or cold reset and state changing on an address line of optionally installed EEPROM memory.</p><p><strong>Beware!</strong> Before you grab a soldering iron and happily decide to install the modification in your favourite C64 remember, that any hardware alteration can lead to unintended damage.</p><p><strong>What will be required for this project?</strong></p><p>A USB capable PC, which will run the official Arduino toolkit (<a href="https://www.arduino.cc/">https://www.arduino.cc/</a>). Of course the Arduino Pro Mini circuit is the key element of this project. When purchasing, take care to select the correct version. There are two variants, one runs on 5V and the other on 3.3V. Since the Commodore 64 also uses 5V, it&#x2019;s necessary to choose that version.</p><p>To be able to program the circuit we&#x2019;ll also need an USB to RS232 adapter (don&#x2019;t confuse one with UART programmer, which looks almost identically). I recommend FDTI232 programmers, which work without a hitch on the latest OS&#x2019;es and are also equipped with DTR output, &#xA0;allowing automatically reset the Arduino before programming begins. Unfortunately most of available tutorials fail to mention that and asks the user to manually press reset button in a very speciffic moment, which is very tedious and can cause a rageous reaction, when you&#x2019;re attempting to sync it correctly for the twentieth time.</p><p>Aside those two devices we&#x2019;ll also need 5 or 6 wires to connect all the necessary signals, depending on if we also want to use the rom selector.</p><h3 id="programming-the-arduino">Programming the Arduino</h3><p>After installing the toolkit and adapter driver, start up the Arduino IDE and paste in the code listing attached with this article.</p>
        <div class="kg-card kg-file-card ">
            <a class="kg-file-card-container" href="https://gohanks.com/content/files/2023/10/c64_reset.ino" title="Download" download>
                <div class="kg-file-card-contents">
                    <div class="kg-file-card-title">C64 reset</div>
                    <div class="kg-file-card-caption">Arduino source code</div>
                    <div class="kg-file-card-metadata">
                        <div class="kg-file-card-filename">c64_reset.ino</div>
                        <div class="kg-file-card-filesize">8 KB</div>
                    </div>
                </div>
                <div class="kg-file-card-icon">
                    <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24"><defs><style>.a{fill:none;stroke:currentColor;stroke-linecap:round;stroke-linejoin:round;stroke-width:1.5px;}</style></defs><title>download-circle</title><polyline class="a" points="8.25 14.25 12 18 15.75 14.25"/><line class="a" x1="12" y1="6.75" x2="12" y2="18"/><circle class="a" cx="12" cy="12" r="11.25"/></svg>
                </div>
            </a>
        </div>
        <p>Now let&#x2019;s connect the Arduino Pro Mini in a following fashion:</p><p>- ground on the adapter to ground of Arduino,</p><p>- Vcc on the adapter to Vcc on Arduino,</p><p>- Rx on the adapter to Tx on Arduino,</p><p>- Tx on the adapter to Rx on Arduino,</p><p>- DTR on the adapter to DTR or Reset on Arduino.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://gohanks.com/content/images/2023/10/1.png" class="kg-image" alt="Connections scheme" loading="lazy" width="438" height="356"><figcaption>Connections scheme</figcaption></figure><p>Next select propper circuit board from the menu <strong>Tools &gt; Circuit board&#x2026; &gt; Arduino Pro or Pro Mini</strong>. The processor we&#x2019;re using <strong>Tools &gt; Processor&#x2026; &gt; Atmega 328p (5V, 16MHz)</strong> and the adapter <strong>Tools &gt; Programmer &gt; AVRISP mk II</strong>.</p><p>If everything was configured and connected correctly, after pressing Upload button, the Arduino should blink it&#x2019;s diodes a few times and the IDE will notify us that the upload was successful. If any error occurs, make sure all the steps up to now were done correctly.</p><p><strong>Installation</strong></p><p>Now it&#x2019;s time to proceed with the hardware part of the solution. We have to connect the board accoarding to the following scheme:</p><ul><li>Vcc on Arduino to +5V line on the C64 motherboard,</li><li> GND on Arduino to GND on the C64 motherboard,</li><li> A0 analog I/O line to RESTORE button line on the C64 motherboard,</li><li>digital I/O line 3 to CPU Reset line on the C64 motherboard,</li><li>digital I/O line 4 to /EXROM line on the C64 motherboard,</li><li>digital I/O line 5 to leg 27 of the EEPROM memory (optionally).</li></ul><p>Sounds complicated? Unfortunatelly that&#x2019;s the hardest part of the whole mod and because a lot of different versions of the C64 motherboard exsist, it&#x2019;s very probable that you&#x2019;ll need some aid from the service manual to find where exactly are all the signals on the one you have.</p><p>Anyway, for now we&#x2019;ll use a popular C64C motherboard variant as an example &#x2013; Assy No. 250469 Rev. B.</p><p>First we need to supply 5V to the circuitboard, which we&#x2019;ll find in a lot of places all over the C64 board. I went with a comfortable location right beside the POWER LED pins. Looking at the motherboard from the usual spot we take when we use the Commodore, +5V can be located on the first free soldering point on the left of the LED pins. &#xA0;In the same line just beside there&#x2019;s also a point with ground. It&#x2019;s worth to make sure and confirm the correct values with a Voltometer.</p><figure class="kg-card kg-image-card"><img src="https://gohanks.com/content/images/2023/10/IMG_20171126_132531.jpg" class="kg-image" alt loading="lazy" width="520" height="469"></figure><p>The RESTORE signal is also relatively easy to find on this motherboard. We&#x2019;ll locate it almost at the bottom edge of the board, on one of the R17 resistor legs (the one near the neighbouring capacitor). Why use the RESTORE button? Because it&#x2019;s the only one that&#x2019;s has a direct connection on the motherboard and isn&#x2019;t in any way coded.</p><figure class="kg-card kg-image-card"><img src="https://gohanks.com/content/images/2023/10/IMG_20171126_132514.jpg" class="kg-image" alt loading="lazy" width="520" height="417"></figure><p>The RESET line can be located on the anode of CR5 diode, which you&#x2019;ll find just above the character ROM. Unfortunately it&#x2019;s difficult to solder a wire in from the upper side of the board, which gives us two options, either to move the diode, or to solder the wire from the backside, which I did.</p><figure class="kg-card kg-image-card"><img src="https://gohanks.com/content/images/2023/10/IMG_20171126_132311.jpg" class="kg-image" alt loading="lazy" width="520" height="429"></figure><p>The most difficult to locate for me was the /EXROM line. On my motherboard the soldering point was covered up by a sticker. Also near the bottom edge between PLA and the VIC-II chips you&#x2019;ll find five soldering points in a row. Counting from the left, the fourth one is the /EXROM line.</p><figure class="kg-card kg-image-card"><img src="https://gohanks.com/content/images/2023/10/IMG_20171126_132345.jpg" class="kg-image" alt loading="lazy" width="520" height="390"></figure><p>If your C64 is also equipped with a dual ROM, it&#x2019;s possible to connect one of it&#x2019;s legs to the I/O line 5. The attached code allows to switch between two ROM locations, but it&#x2019;s possible to add in support for four. Keep also in mind that in the old C64 models Basic and Kernal were located in separate ROM chips, unlike the C64C where they only use one.</p><p>If everything was connected correctly, you can test the solution.</p><h3 id="how-does-it-work">How does it work?</h3><p>The mod adds a few functions to our C64, depending on how long we&#x2019;ll press the RESTORE button. Pressing it for two to four seconds, executes a so called warm reset, which starts the Basic setup routine and redraws the screen. If that&#x2019;s not sufficient, because let&#x2019;s say part of the memory was overwritten by users code, it&#x2019;s possible to do a longer, four to seven seconds press and execute a cold reset instead. This takes the Commodore through the complete startup routine and works in a same fashion as a reset button on a cartridge. If the computer has the dual ROM installed and connected, it&#x2019;s also possible to press RESTORE for seven to ten seconds and this in turn will do a cold reset and additionally switch the currently used ROM location.</p><p>For cartridge compatibility purposes I&#x2019;ve also added the ability to start up the machine using the second ROM, by pressing the RESTORE button during the power on.<br></p><p>And voila! This way we&#x2019;ve supplied our good old C64 with a neat CTRL+ALT+DELETE equivalent without drilling any holes or damaging the housing. To make the solution more elegant and easier to dismount it&#x2019;s possible to use goldpin connector instead of directly soldering in the wires.</p>]]></content:encoded></item><item><title><![CDATA[Coming soon]]></title><description><![CDATA[<p>This is Gohanks&apos; Retro Corner, a brand new site by Gohanks that&apos;s just getting started. Things will be up and running here shortly, but you can <a href="#/portal/">subscribe</a> in the meantime if you&apos;d like to stay up to date and receive emails when new content is</p>]]></description><link>https://gohanks.com/coming-soon/</link><guid isPermaLink="false">64562126bedff70001080212</guid><category><![CDATA[News]]></category><dc:creator><![CDATA[Gohanks]]></dc:creator><pubDate>Sat, 06 May 2023 09:43:02 GMT</pubDate><media:content url="https://static.ghost.org/v4.0.0/images/feature-image.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://static.ghost.org/v4.0.0/images/feature-image.jpg" alt="Coming soon"><p>This is Gohanks&apos; Retro Corner, a brand new site by Gohanks that&apos;s just getting started. Things will be up and running here shortly, but you can <a href="#/portal/">subscribe</a> in the meantime if you&apos;d like to stay up to date and receive emails when new content is published!</p>]]></content:encoded></item></channel></rss>