via-macii.c 13.6 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0
Linus Torvalds's avatar
Linus Torvalds committed
2 3 4 5 6 7 8 9 10 11 12 13 14
/*
 * Device driver for the via ADB on (many) Mac II-class machines
 *
 * Based on the original ADB keyboard handler Copyright (c) 1997 Alan Cox
 * Also derived from code Copyright (C) 1996 Paul Mackerras.
 *
 * With various updates provided over the years by Michael Schmitz,
 * Guideo Koerber and others.
 *
 * Rewrite for Unified ADB by Joshua M. Thompson (funaho@jurai.org)
 *
 * 1999-08-02 (jmt) - Initial rewrite for Unified ADB.
 * 2000-03-29 Tony Mantler <tonym@mac.linux-m68k.org>
15
 *            - Big overhaul, should actually work now.
16
 * 2006-12-31 Finn Thain - Another overhaul.
Finn Thain's avatar
Finn Thain committed
17 18 19 20 21 22 23 24
 *
 * Suggested reading:
 *   Inside Macintosh, ch. 5 ADB Manager
 *   Guide to the Macinstosh Family Hardware, ch. 8 Apple Desktop Bus
 *   Rockwell R6522 VIA datasheet
 *
 * Apple's "ADB Analyzer" bus sniffer is invaluable:
 *   ftp://ftp.apple.com/developer/Tool_Chest/Devices_-_Hardware/Apple_Desktop_Bus/
Linus Torvalds's avatar
Linus Torvalds committed
25
 */
26

Linus Torvalds's avatar
Linus Torvalds committed
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
#include <stdarg.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/adb.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <asm/macintosh.h>
#include <asm/macints.h>
#include <asm/mac_via.h>

static volatile unsigned char *via;

/* VIA registers - spaced 0x200 bytes apart */
#define RS		0x200		/* skip between registers */
#define B		0		/* B-side data */
#define A		RS		/* A-side data */
#define DIRB		(2*RS)		/* B-side direction (1=output) */
#define DIRA		(3*RS)		/* A-side direction (1=output) */
#define T1CL		(4*RS)		/* Timer 1 ctr/latch (low 8 bits) */
#define T1CH		(5*RS)		/* Timer 1 counter (high 8 bits) */
#define T1LL		(6*RS)		/* Timer 1 latch (low 8 bits) */
#define T1LH		(7*RS)		/* Timer 1 latch (high 8 bits) */
#define T2CL		(8*RS)		/* Timer 2 ctr/latch (low 8 bits) */
#define T2CH		(9*RS)		/* Timer 2 counter (high 8 bits) */
#define SR		(10*RS)		/* Shift register */
#define ACR		(11*RS)		/* Auxiliary control register */
#define PCR		(12*RS)		/* Peripheral control register */
#define IFR		(13*RS)		/* Interrupt flag register */
#define IER		(14*RS)		/* Interrupt enable register */
#define ANH		(15*RS)		/* A-side data, no handshake */

/* Bits in B data register: all active low */
Finn Thain's avatar
Finn Thain committed
61
#define CTLR_IRQ	0x08		/* Controller rcv status (input) */
Linus Torvalds's avatar
Linus Torvalds committed
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
#define ST_MASK		0x30		/* mask for selecting ADB state bits */

/* Bits in ACR */
#define SR_CTRL		0x1c		/* Shift register control bits */
#define SR_EXT		0x0c		/* Shift on external clock */
#define SR_OUT		0x10		/* Shift out if 1 */

/* Bits in IFR and IER */
#define IER_SET		0x80		/* set bits in IER */
#define IER_CLR		0		/* clear bits in IER */
#define SR_INT		0x04		/* Shift register full/empty */

/* ADB transaction states according to GMHW */
#define ST_CMD		0x00		/* ADB state: command byte */
#define ST_EVEN		0x10		/* ADB state: even data byte */
#define ST_ODD		0x20		/* ADB state: odd data byte */
#define ST_IDLE		0x30		/* ADB state: idle, nothing to send */

80
static int macii_init_via(void);
Linus Torvalds's avatar
Linus Torvalds committed
81
static void macii_start(void);
82
static irqreturn_t macii_interrupt(int irq, void *arg);
Linus Torvalds's avatar
Linus Torvalds committed
83 84 85 86 87 88 89 90 91 92 93
static void macii_queue_poll(void);

static int macii_probe(void);
static int macii_init(void);
static int macii_send_request(struct adb_request *req, int sync);
static int macii_write(struct adb_request *req);
static int macii_autopoll(int devs);
static void macii_poll(void);
static int macii_reset_bus(void);

struct adb_driver via_macii_driver = {
94 95 96 97 98 99 100
	.name         = "Mac II",
	.probe        = macii_probe,
	.init         = macii_init,
	.send_request = macii_send_request,
	.autopoll     = macii_autopoll,
	.poll         = macii_poll,
	.reset_bus    = macii_reset_bus,
Linus Torvalds's avatar
Linus Torvalds committed
101 102 103 104 105 106 107 108 109
};

static enum macii_state {
	idle,
	sending,
	reading,
	read_done,
} macii_state;

Finn Thain's avatar
Finn Thain committed
110 111 112
static struct adb_request *current_req; /* first request struct in the queue */
static struct adb_request *last_req;     /* last request struct in the queue */
static unsigned char reply_buf[16];        /* storage for autopolled replies */
113
static unsigned char *reply_ptr;     /* next byte in reply_buf or req->reply */
Finn Thain's avatar
Finn Thain committed
114 115 116 117 118 119 120 121 122
static int reading_reply;        /* store reply in reply_buf else req->reply */
static int data_index;      /* index of the next byte to send from req->data */
static int reply_len; /* number of bytes received in reply_buf or req->reply */
static int status;          /* VIA's ADB status bits captured upon interrupt */
static int last_status;              /* status bits as at previous interrupt */
static int srq_asserted;     /* have to poll for the device that asserted it */
static int command_byte;         /* the most recent command byte transmitted */
static int autopoll_devs;      /* bits set are device addresses to be polled */

Linus Torvalds's avatar
Linus Torvalds committed
123 124 125
/* Check for MacII style ADB */
static int macii_probe(void)
{
126 127
	if (macintosh_config->adb_type != MAC_ADB_II)
		return -ENODEV;
Linus Torvalds's avatar
Linus Torvalds committed
128 129 130

	via = via1;

131
	pr_info("adb: Mac II ADB Driver v1.0 for Unified ADB\n");
Linus Torvalds's avatar
Linus Torvalds committed
132 133 134 135 136 137 138 139
	return 0;
}

/* Initialize the driver */
int macii_init(void)
{
	unsigned long flags;
	int err;
140

Linus Torvalds's avatar
Linus Torvalds committed
141
	local_irq_save(flags);
142

Linus Torvalds's avatar
Linus Torvalds committed
143
	err = macii_init_via();
144 145
	if (err)
		goto out;
Linus Torvalds's avatar
Linus Torvalds committed
146

147
	err = request_irq(IRQ_MAC_ADB, macii_interrupt, 0, "ADB",
Linus Torvalds's avatar
Linus Torvalds committed
148
			  macii_interrupt);
149 150
	if (err)
		goto out;
Linus Torvalds's avatar
Linus Torvalds committed
151 152

	macii_state = idle;
Finn Thain's avatar
Finn Thain committed
153
out:
Linus Torvalds's avatar
Linus Torvalds committed
154
	local_irq_restore(flags);
Finn Thain's avatar
Finn Thain committed
155
	return err;
Linus Torvalds's avatar
Linus Torvalds committed
156 157
}

158
/* initialize the hardware */
Linus Torvalds's avatar
Linus Torvalds committed
159 160 161 162
static int macii_init_via(void)
{
	unsigned char x;

Finn Thain's avatar
Finn Thain committed
163 164
	/* We want CTLR_IRQ as input and ST_EVEN | ST_ODD as output lines. */
	via[DIRB] = (via[DIRB] | ST_EVEN | ST_ODD) & ~CTLR_IRQ;
Linus Torvalds's avatar
Linus Torvalds committed
165 166 167

	/* Set up state: idle */
	via[B] |= ST_IDLE;
168
	last_status = via[B] & (ST_MASK | CTLR_IRQ);
Linus Torvalds's avatar
Linus Torvalds committed
169 170 171 172 173 174 175 176 177 178

	/* Shift register on input */
	via[ACR] = (via[ACR] & ~SR_CTRL) | SR_EXT;

	/* Wipe any pending data and int */
	x = via[SR];

	return 0;
}

Finn Thain's avatar
Finn Thain committed
179
/* Send an ADB poll (Talk Register 0 command prepended to the request queue) */
Linus Torvalds's avatar
Linus Torvalds committed
180 181
static void macii_queue_poll(void)
{
Finn Thain's avatar
Finn Thain committed
182 183 184 185 186 187 188 189 190 191
	/* No point polling the active device as it will never assert SRQ, so
	 * poll the next device in the autopoll list. This could leave us
	 * stuck in a polling loop if an unprobed device is asserting SRQ.
	 * In theory, that could only happen if a device was plugged in after
	 * probing started. Unplugging it again will break the cycle.
	 * (Simply polling the next higher device often ends up polling almost
	 * every device (after wrapping around), which takes too long.)
	 */
	int device_mask;
	int next_device;
Linus Torvalds's avatar
Linus Torvalds committed
192 193
	static struct adb_request req;

194 195
	if (!autopoll_devs)
		return;
Linus Torvalds's avatar
Linus Torvalds committed
196

Finn Thain's avatar
Finn Thain committed
197 198 199 200 201
	device_mask = (1 << (((command_byte & 0xF0) >> 4) + 1)) - 1;
	if (autopoll_devs & ~device_mask)
		next_device = ffs(autopoll_devs & ~device_mask) - 1;
	else
		next_device = ffs(autopoll_devs) - 1;
Linus Torvalds's avatar
Linus Torvalds committed
202

203
	adb_request(&req, NULL, ADBREQ_NOSEND, 1, ADB_READREG(next_device, 0));
Linus Torvalds's avatar
Linus Torvalds committed
204

Finn Thain's avatar
Finn Thain committed
205 206 207 208
	req.sent = 0;
	req.complete = 0;
	req.reply_len = 0;
	req.next = current_req;
Linus Torvalds's avatar
Linus Torvalds committed
209 210

	if (current_req != NULL) {
Finn Thain's avatar
Finn Thain committed
211
		current_req = &req;
Linus Torvalds's avatar
Linus Torvalds committed
212
	} else {
Finn Thain's avatar
Finn Thain committed
213 214
		current_req = &req;
		last_req = &req;
Linus Torvalds's avatar
Linus Torvalds committed
215 216 217 218 219 220
	}
}

/* Send an ADB request; if sync, poll out the reply 'till it's done */
static int macii_send_request(struct adb_request *req, int sync)
{
Finn Thain's avatar
Finn Thain committed
221
	int err;
Linus Torvalds's avatar
Linus Torvalds committed
222

Finn Thain's avatar
Finn Thain committed
223
	err = macii_write(req);
224 225
	if (err)
		return err;
Finn Thain's avatar
Finn Thain committed
226

227
	if (sync)
228
		while (!req->complete)
Finn Thain's avatar
Finn Thain committed
229 230
			macii_poll();

231
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
232 233
}

Finn Thain's avatar
Finn Thain committed
234
/* Send an ADB request (append to request queue) */
Linus Torvalds's avatar
Linus Torvalds committed
235 236
static int macii_write(struct adb_request *req)
{
237 238
	unsigned long flags;

Linus Torvalds's avatar
Linus Torvalds committed
239 240 241 242
	if (req->nbytes < 2 || req->data[0] != ADB_PACKET || req->nbytes > 15) {
		req->complete = 1;
		return -EINVAL;
	}
243

244
	req->next = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
245 246 247 248
	req->sent = 0;
	req->complete = 0;
	req->reply_len = 0;

249 250
	local_irq_save(flags);

Linus Torvalds's avatar
Linus Torvalds committed
251 252 253 254 255 256
	if (current_req != NULL) {
		last_req->next = req;
		last_req = req;
	} else {
		current_req = req;
		last_req = req;
257 258
		if (macii_state == idle)
			macii_start();
Linus Torvalds's avatar
Linus Torvalds committed
259
	}
260 261 262

	local_irq_restore(flags);

Linus Torvalds's avatar
Linus Torvalds committed
263 264 265 266 267 268
	return 0;
}

/* Start auto-polling */
static int macii_autopoll(int devs)
{
Finn Thain's avatar
Finn Thain committed
269 270 271 272 273 274 275
	static struct adb_request req;
	unsigned long flags;
	int err = 0;

	/* bit 1 == device 1, and so on. */
	autopoll_devs = devs & 0xFFFE;

276 277
	if (!autopoll_devs)
		return 0;
Finn Thain's avatar
Finn Thain committed
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293

	local_irq_save(flags);

	if (current_req == NULL) {
		/* Send a Talk Reg 0. The controller will repeatedly transmit
		 * this as long as it is idle.
		 */
		adb_request(&req, NULL, ADBREQ_NOSEND, 1,
		            ADB_READREG(ffs(autopoll_devs) - 1, 0));
		err = macii_write(&req);
	}

	local_irq_restore(flags);
	return err;
}

294 295
static inline int need_autopoll(void)
{
Finn Thain's avatar
Finn Thain committed
296 297 298 299 300 301 302
	/* Was the last command Talk Reg 0
	 * and is the target on the autopoll list?
	 */
	if ((command_byte & 0x0F) == 0x0C &&
	    ((1 << ((command_byte & 0xF0) >> 4)) & autopoll_devs))
		return 0;
	return 1;
Linus Torvalds's avatar
Linus Torvalds committed
303 304 305 306 307
}

/* Prod the chip without interrupts */
static void macii_poll(void)
{
Finn Thain's avatar
Finn Thain committed
308
	macii_interrupt(0, NULL);
Linus Torvalds's avatar
Linus Torvalds committed
309 310 311 312 313 314
}

/* Reset the bus */
static int macii_reset_bus(void)
{
	static struct adb_request req;
315

Linus Torvalds's avatar
Linus Torvalds committed
316
	/* Command = 0, Address = ignored */
317 318
	adb_request(&req, NULL, ADBREQ_NOSEND, 1, ADB_BUSRESET);
	macii_send_request(&req, 1);
Linus Torvalds's avatar
Linus Torvalds committed
319

Finn Thain's avatar
Finn Thain committed
320 321 322
	/* Don't want any more requests during the Global Reset low time. */
	udelay(3000);

Linus Torvalds's avatar
Linus Torvalds committed
323 324 325 326 327 328 329 330 331 332
	return 0;
}

/* Start sending ADB packet */
static void macii_start(void)
{
	struct adb_request *req;

	req = current_req;

Finn Thain's avatar
Finn Thain committed
333 334 335
	/* Now send it. Be careful though, that first byte of the request
	 * is actually ADB_PACKET; the real data begins at index 1!
	 * And req->nbytes is the number of bytes of real data plus one.
Linus Torvalds's avatar
Linus Torvalds committed
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
	 */

	/* store command byte */
	command_byte = req->data[1];
	/* Output mode */
	via[ACR] |= SR_OUT;
	/* Load data */
	via[SR] = req->data[1];
	/* set ADB state to 'command' */
	via[B] = (via[B] & ~ST_MASK) | ST_CMD;

	macii_state = sending;
	data_index = 2;
}

/*
Finn Thain's avatar
Finn Thain committed
352 353 354 355
 * The notorious ADB interrupt handler - does all of the protocol handling.
 * Relies on the ADB controller sending and receiving data, thereby
 * generating shift register interrupts (SR_INT) for us. This means there has
 * to be activity on the ADB bus. The chip will poll to achieve this.
Linus Torvalds's avatar
Linus Torvalds committed
356 357
 *
 * The basic ADB state machine was left unchanged from the original MacII code
358
 * by Alan Cox, which was based on the CUDA driver for PowerMac.
Finn Thain's avatar
Finn Thain committed
359 360 361 362 363 364 365
 * The syntax of the ADB status lines is totally different on MacII,
 * though. MacII uses the states Command -> Even -> Odd -> Even ->...-> Idle
 * for sending and Idle -> Even -> Odd -> Even ->...-> Idle for receiving.
 * Start and end of a receive packet are signalled by asserting /IRQ on the
 * interrupt line (/IRQ means the CTLR_IRQ bit in port B; not to be confused
 * with the VIA shift register interrupt. /IRQ never actually interrupts the
 * processor, it's just an ordinary input.)
Linus Torvalds's avatar
Linus Torvalds committed
366
 */
367
static irqreturn_t macii_interrupt(int irq, void *arg)
Linus Torvalds's avatar
Linus Torvalds committed
368
{
Finn Thain's avatar
Finn Thain committed
369
	int x;
Linus Torvalds's avatar
Linus Torvalds committed
370
	struct adb_request *req;
371 372 373
	unsigned long flags;

	local_irq_save(flags);
Linus Torvalds's avatar
Linus Torvalds committed
374

Finn Thain's avatar
Finn Thain committed
375 376 377 378
	if (!arg) {
		/* Clear the SR IRQ flag when polling. */
		if (via[IFR] & SR_INT)
			via[IFR] = SR_INT;
379 380
		else {
			local_irq_restore(flags);
Finn Thain's avatar
Finn Thain committed
381
			return IRQ_NONE;
382
		}
Linus Torvalds's avatar
Linus Torvalds committed
383 384
	}

Finn Thain's avatar
Finn Thain committed
385
	last_status = status;
386
	status = via[B] & (ST_MASK | CTLR_IRQ);
Linus Torvalds's avatar
Linus Torvalds committed
387 388

	switch (macii_state) {
389 390 391 392 393 394 395
	case idle:
		if (reading_reply) {
			reply_ptr = current_req->reply;
		} else {
			WARN_ON(current_req);
			reply_ptr = reply_buf;
		}
Finn Thain's avatar
Finn Thain committed
396

397
		x = via[SR];
Linus Torvalds's avatar
Linus Torvalds committed
398

399 400 401 402 403 404 405 406 407 408 409 410
		if ((status & CTLR_IRQ) && (x == 0xFF)) {
			/* Bus timeout without SRQ sequence:
			 *     data is "FF" while CTLR_IRQ is "H"
			 */
			reply_len = 0;
			srq_asserted = 0;
			macii_state = read_done;
		} else {
			macii_state = reading;
			*reply_ptr = x;
			reply_len = 1;
		}
Linus Torvalds's avatar
Linus Torvalds committed
411

412 413 414
		/* set ADB state = even for first data byte */
		via[B] = (via[B] & ~ST_MASK) | ST_EVEN;
		break;
Linus Torvalds's avatar
Linus Torvalds committed
415

416 417 418 419 420
	case sending:
		req = current_req;
		if (data_index >= req->nbytes) {
			req->sent = 1;
			macii_state = idle;
Finn Thain's avatar
Finn Thain committed
421

422 423
			if (req->reply_expected) {
				reading_reply = 1;
Linus Torvalds's avatar
Linus Torvalds committed
424
			} else {
425 426 427 428
				req->complete = 1;
				current_req = req->next;
				if (req->done)
					(*req->done)(req);
Linus Torvalds's avatar
Linus Torvalds committed
429

430 431 432 433
				if (current_req)
					macii_start();
				else if (need_autopoll())
					macii_autopoll(autopoll_devs);
Finn Thain's avatar
Finn Thain committed
434 435
			}

436 437 438 439 440 441
			if (macii_state == idle) {
				/* reset to shift in */
				via[ACR] &= ~SR_OUT;
				x = via[SR];
				/* set ADB state idle - might get SRQ */
				via[B] = (via[B] & ~ST_MASK) | ST_IDLE;
Linus Torvalds's avatar
Linus Torvalds committed
442
			}
443 444
		} else {
			via[SR] = req->data[data_index++];
Linus Torvalds's avatar
Linus Torvalds committed
445

446 447 448 449 450 451 452 453 454
			if ((via[B] & ST_MASK) == ST_CMD) {
				/* just sent the command byte, set to EVEN */
				via[B] = (via[B] & ~ST_MASK) | ST_EVEN;
			} else {
				/* invert state bits, toggle ODD/EVEN */
				via[B] ^= ST_MASK;
			}
		}
		break;
Linus Torvalds's avatar
Linus Torvalds committed
455

456 457 458 459 460 461 462 463 464 465 466 467 468 469
	case reading:
		x = via[SR];
		WARN_ON((status & ST_MASK) == ST_CMD ||
			(status & ST_MASK) == ST_IDLE);

		/* Bus timeout with SRQ sequence:
		 *     data is "XX FF"      while CTLR_IRQ is "L L"
		 * End of packet without SRQ sequence:
		 *     data is "XX...YY 00" while CTLR_IRQ is "L...H L"
		 * End of packet SRQ sequence:
		 *     data is "XX...YY 00" while CTLR_IRQ is "L...L L"
		 * (where XX is the first response byte and
		 * YY is the last byte of valid response data.)
		 */
Finn Thain's avatar
Finn Thain committed
470

471 472 473 474 475 476 477 478 479 480 481 482 483 484
		srq_asserted = 0;
		if (!(status & CTLR_IRQ)) {
			if (x == 0xFF) {
				if (!(last_status & CTLR_IRQ)) {
					macii_state = read_done;
					reply_len = 0;
					srq_asserted = 1;
				}
			} else if (x == 0x00) {
				macii_state = read_done;
				if (!(last_status & CTLR_IRQ))
					srq_asserted = 1;
			}
		}
Linus Torvalds's avatar
Linus Torvalds committed
485

486 487 488 489 490 491
		if (macii_state == reading &&
		    reply_len < ARRAY_SIZE(reply_buf)) {
			reply_ptr++;
			*reply_ptr = x;
			reply_len++;
		}
Linus Torvalds's avatar
Linus Torvalds committed
492

493 494 495
		/* invert state bits, toggle ODD/EVEN */
		via[B] ^= ST_MASK;
		break;
Linus Torvalds's avatar
Linus Torvalds committed
496

497 498
	case read_done:
		x = via[SR];
Finn Thain's avatar
Finn Thain committed
499

500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524
		if (reading_reply) {
			reading_reply = 0;
			req = current_req;
			req->reply_len = reply_len;
			req->complete = 1;
			current_req = req->next;
			if (req->done)
				(*req->done)(req);
		} else if (reply_len && autopoll_devs)
			adb_input(reply_buf, reply_len, 0);

		macii_state = idle;

		/* SRQ seen before, initiate poll now */
		if (srq_asserted)
			macii_queue_poll();

		if (current_req)
			macii_start();
		else if (need_autopoll())
			macii_autopoll(autopoll_devs);

		if (macii_state == idle)
			via[B] = (via[B] & ~ST_MASK) | ST_IDLE;
		break;
Linus Torvalds's avatar
Linus Torvalds committed
525

526
	default:
Linus Torvalds's avatar
Linus Torvalds committed
527 528
		break;
	}
Finn Thain's avatar
Finn Thain committed
529

530
	local_irq_restore(flags);
Linus Torvalds's avatar
Linus Torvalds committed
531 532
	return IRQ_HANDLED;
}