| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
 | 2 |  * Device driver for the IIsi-style ADB on some Mac LC and II-class machines | 
 | 3 |  * | 
 | 4 |  * Based on via-cuda.c and via-macii.c, as well as the original | 
 | 5 |  * adb-bus.c, which in turn is somewhat influenced by (but uses no | 
 | 6 |  * code from) the NetBSD HWDIRECT ADB code.  Original IIsi driver work | 
 | 7 |  * was done by Robert Thompson and integrated into the old style | 
 | 8 |  * driver by Michael Schmitz. | 
 | 9 |  * | 
 | 10 |  * Original sources (c) Alan Cox, Paul Mackerras, and others. | 
 | 11 |  * | 
 | 12 |  * Rewritten for Unified ADB by David Huggins-Daines <dhd@debian.org> | 
 | 13 |  *  | 
 | 14 |  * 7/13/2000- extensive changes by Andrew McPherson <andrew@macduff.dhs.org> | 
 | 15 |  * Works about 30% of the time now. | 
 | 16 |  */ | 
 | 17 |  | 
 | 18 | #include <linux/types.h> | 
 | 19 | #include <linux/errno.h> | 
 | 20 | #include <linux/kernel.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 21 | #include <linux/adb.h> | 
 | 22 | #include <linux/cuda.h> | 
 | 23 | #include <linux/delay.h> | 
 | 24 | #include <linux/interrupt.h> | 
 | 25 | #include <asm/macintosh.h> | 
 | 26 | #include <asm/macints.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 27 | #include <asm/mac_via.h> | 
 | 28 |  | 
 | 29 | static volatile unsigned char *via; | 
 | 30 |  | 
 | 31 | /* VIA registers - spaced 0x200 bytes apart - only the ones we actually use */ | 
 | 32 | #define RS		0x200		/* skip between registers */ | 
 | 33 | #define B		0		/* B-side data */ | 
 | 34 | #define A		RS		/* A-side data */ | 
 | 35 | #define DIRB		(2*RS)		/* B-side direction (1=output) */ | 
 | 36 | #define DIRA		(3*RS)		/* A-side direction (1=output) */ | 
 | 37 | #define SR		(10*RS)		/* Shift register */ | 
 | 38 | #define ACR		(11*RS)		/* Auxiliary control register */ | 
 | 39 | #define IFR		(13*RS)		/* Interrupt flag register */ | 
 | 40 | #define IER		(14*RS)		/* Interrupt enable register */ | 
 | 41 |  | 
 | 42 | /* Bits in B data register: all active low */ | 
 | 43 | #define TREQ		0x08		/* Transfer request (input) */ | 
 | 44 | #define TACK		0x10		/* Transfer acknowledge (output) */ | 
 | 45 | #define TIP		0x20		/* Transfer in progress (output) */ | 
 | 46 | #define ST_MASK		0x30		/* mask for selecting ADB state bits */ | 
 | 47 |  | 
 | 48 | /* Bits in ACR */ | 
 | 49 | #define SR_CTRL		0x1c		/* Shift register control bits */ | 
 | 50 | #define SR_EXT		0x0c		/* Shift on external clock */ | 
 | 51 | #define SR_OUT		0x10		/* Shift out if 1 */ | 
 | 52 |  | 
 | 53 | /* Bits in IFR and IER */ | 
 | 54 | #define IER_SET		0x80		/* set bits in IER */ | 
 | 55 | #define IER_CLR		0		/* clear bits in IER */ | 
 | 56 | #define SR_INT		0x04		/* Shift register full/empty */ | 
 | 57 | #define SR_DATA		0x08		/* Shift register data */ | 
 | 58 | #define SR_CLOCK	0x10		/* Shift register clock */ | 
 | 59 |  | 
 | 60 | #define ADB_DELAY 150 | 
 | 61 |  | 
 | 62 | #undef DEBUG_MACIISI_ADB | 
 | 63 |  | 
| Olaf Hering | 8727585 | 2007-02-10 21:35:12 +0100 | [diff] [blame] | 64 | static struct adb_request* current_req; | 
 | 65 | static struct adb_request* last_req; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 66 | static unsigned char maciisi_rbuf[16]; | 
| Olaf Hering | 8727585 | 2007-02-10 21:35:12 +0100 | [diff] [blame] | 67 | static unsigned char *reply_ptr; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 68 | static int data_index; | 
 | 69 | static int reading_reply; | 
 | 70 | static int reply_len; | 
 | 71 | static int tmp; | 
 | 72 | static int need_sync; | 
 | 73 |  | 
 | 74 | static enum maciisi_state { | 
 | 75 |     idle, | 
 | 76 |     sending, | 
 | 77 |     reading, | 
 | 78 | } maciisi_state; | 
 | 79 |  | 
 | 80 | static int maciisi_probe(void); | 
 | 81 | static int maciisi_init(void); | 
 | 82 | static int maciisi_send_request(struct adb_request* req, int sync); | 
 | 83 | static void maciisi_sync(struct adb_request *req); | 
 | 84 | static int maciisi_write(struct adb_request* req); | 
| David Howells | 7d12e78 | 2006-10-05 14:55:46 +0100 | [diff] [blame] | 85 | static irqreturn_t maciisi_interrupt(int irq, void* arg); | 
 | 86 | static void maciisi_input(unsigned char *buf, int nb); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 87 | static int maciisi_init_via(void); | 
 | 88 | static void maciisi_poll(void); | 
 | 89 | static int maciisi_start(void); | 
 | 90 |  | 
 | 91 | struct adb_driver via_maciisi_driver = { | 
 | 92 | 	"Mac IIsi", | 
 | 93 | 	maciisi_probe, | 
 | 94 | 	maciisi_init, | 
 | 95 | 	maciisi_send_request, | 
 | 96 | 	NULL, /* maciisi_adb_autopoll, */ | 
 | 97 | 	maciisi_poll, | 
 | 98 | 	NULL /* maciisi_reset_adb_bus */ | 
 | 99 | }; | 
 | 100 |  | 
 | 101 | static int | 
 | 102 | maciisi_probe(void) | 
 | 103 | { | 
 | 104 | 	if (macintosh_config->adb_type != MAC_ADB_IISI) | 
 | 105 | 		return -ENODEV; | 
 | 106 |  | 
 | 107 | 	via = via1; | 
 | 108 | 	return 0; | 
 | 109 | } | 
 | 110 |  | 
 | 111 | static int | 
 | 112 | maciisi_init(void) | 
 | 113 | { | 
 | 114 | 	int err; | 
 | 115 |  | 
 | 116 | 	if (via == NULL) | 
 | 117 | 		return -ENODEV; | 
 | 118 |  | 
 | 119 | 	if ((err = maciisi_init_via())) { | 
 | 120 | 		printk(KERN_ERR "maciisi_init: maciisi_init_via() failed, code %d\n", err); | 
 | 121 | 		via = NULL; | 
 | 122 | 		return err; | 
 | 123 | 	} | 
 | 124 |  | 
 | 125 | 	if (request_irq(IRQ_MAC_ADB, maciisi_interrupt, IRQ_FLG_LOCK | IRQ_FLG_FAST,  | 
 | 126 | 			"ADB", maciisi_interrupt)) { | 
 | 127 | 		printk(KERN_ERR "maciisi_init: can't get irq %d\n", IRQ_MAC_ADB); | 
 | 128 | 		return -EAGAIN; | 
 | 129 | 	} | 
 | 130 |  | 
 | 131 | 	printk("adb: Mac IIsi driver v0.2 for Unified ADB.\n"); | 
 | 132 | 	return 0; | 
 | 133 | } | 
 | 134 |  | 
 | 135 | /* Flush data from the ADB controller */ | 
 | 136 | static void | 
 | 137 | maciisi_stfu(void) | 
 | 138 | { | 
 | 139 | 	int status = via[B] & (TIP|TREQ); | 
 | 140 |  | 
 | 141 | 	if (status & TREQ) { | 
 | 142 | #ifdef DEBUG_MACIISI_ADB | 
 | 143 | 		printk (KERN_DEBUG "maciisi_stfu called with TREQ high!\n"); | 
 | 144 | #endif | 
 | 145 | 		return; | 
 | 146 | 	} | 
 | 147 | 	 | 
 | 148 | 	udelay(ADB_DELAY); | 
 | 149 | 	via[ACR] &= ~SR_OUT; | 
 | 150 | 	via[IER] = IER_CLR | SR_INT; | 
 | 151 |  | 
 | 152 | 	udelay(ADB_DELAY); | 
 | 153 |  | 
 | 154 | 	status = via[B] & (TIP|TREQ); | 
 | 155 |  | 
 | 156 | 	if (!(status & TREQ)) | 
 | 157 | 	{ | 
 | 158 | 		via[B] |= TIP; | 
 | 159 |  | 
 | 160 | 		while(1) | 
 | 161 | 		{ | 
 | 162 | 			int poll_timeout = ADB_DELAY * 5; | 
 | 163 | 			/* Poll for SR interrupt */ | 
 | 164 | 			while (!(via[IFR] & SR_INT) && poll_timeout-- > 0) | 
 | 165 | 				status = via[B] & (TIP|TREQ); | 
 | 166 |  | 
 | 167 | 			tmp = via[SR]; /* Clear shift register */ | 
 | 168 | #ifdef DEBUG_MACIISI_ADB | 
 | 169 | 			printk(KERN_DEBUG "maciisi_stfu: status %x timeout %d data %x\n", | 
 | 170 | 			       status, poll_timeout, tmp); | 
 | 171 | #endif	 | 
 | 172 | 			if(via[B] & TREQ) | 
 | 173 | 				break; | 
 | 174 | 	 | 
 | 175 | 			/* ACK on-off */ | 
 | 176 | 			via[B] |= TACK; | 
 | 177 | 			udelay(ADB_DELAY); | 
 | 178 | 			via[B] &= ~TACK; | 
 | 179 | 		} | 
 | 180 |  | 
 | 181 | 		/* end frame */ | 
 | 182 | 		via[B] &= ~TIP; | 
 | 183 | 		udelay(ADB_DELAY); | 
 | 184 | 	} | 
 | 185 |  | 
 | 186 | 	via[IER] = IER_SET | SR_INT;	 | 
 | 187 | } | 
 | 188 |  | 
 | 189 | /* All specifically VIA-related initialization goes here */ | 
 | 190 | static int | 
 | 191 | maciisi_init_via(void) | 
 | 192 | { | 
 | 193 | 	int	i; | 
 | 194 | 	 | 
 | 195 | 	/* Set the lines up. We want TREQ as input TACK|TIP as output */ | 
 | 196 | 	via[DIRB] = (via[DIRB] | TACK | TIP) & ~TREQ; | 
 | 197 | 	/* Shift register on input */ | 
 | 198 | 	via[ACR]  = (via[ACR] & ~SR_CTRL) | SR_EXT; | 
 | 199 | #ifdef DEBUG_MACIISI_ADB | 
 | 200 | 	printk(KERN_DEBUG "maciisi_init_via: initial status %x\n", via[B] & (TIP|TREQ)); | 
 | 201 | #endif | 
 | 202 | 	/* Wipe any pending data and int */ | 
 | 203 | 	tmp = via[SR]; | 
 | 204 | 	/* Enable keyboard interrupts */ | 
 | 205 | 	via[IER] = IER_SET | SR_INT; | 
 | 206 | 	/* Set initial state: idle */ | 
 | 207 | 	via[B] &= ~(TACK|TIP); | 
 | 208 | 	/* Clear interrupt bit */ | 
 | 209 | 	via[IFR] = SR_INT; | 
 | 210 |  | 
 | 211 | 	for(i = 0; i < 60; i++) { | 
 | 212 | 		udelay(ADB_DELAY); | 
 | 213 | 		maciisi_stfu(); | 
 | 214 | 		udelay(ADB_DELAY); | 
 | 215 | 		if(via[B] & TREQ) | 
 | 216 | 			break; | 
 | 217 | 	} | 
 | 218 | 	if (i == 60) | 
 | 219 | 		printk(KERN_ERR "maciisi_init_via: bus jam?\n"); | 
 | 220 |  | 
 | 221 | 	maciisi_state = idle; | 
 | 222 | 	need_sync = 0; | 
 | 223 |  | 
 | 224 | 	return 0; | 
 | 225 | } | 
 | 226 |  | 
 | 227 | /* Send a request, possibly waiting for a reply */ | 
 | 228 | static int | 
 | 229 | maciisi_send_request(struct adb_request* req, int sync) | 
 | 230 | { | 
 | 231 | 	int i; | 
 | 232 |  | 
 | 233 | #ifdef DEBUG_MACIISI_ADB | 
 | 234 | 	static int dump_packet = 0; | 
 | 235 | #endif | 
 | 236 |  | 
 | 237 | 	if (via == NULL) { | 
 | 238 | 		req->complete = 1; | 
 | 239 | 		return -ENXIO; | 
 | 240 | 	} | 
 | 241 |  | 
 | 242 | #ifdef DEBUG_MACIISI_ADB | 
 | 243 | 	if (dump_packet) { | 
 | 244 | 		printk(KERN_DEBUG "maciisi_send_request:"); | 
 | 245 | 		for (i = 0; i < req->nbytes; i++) { | 
 | 246 | 			printk(" %.2x", req->data[i]); | 
 | 247 | 		} | 
 | 248 | 		printk(" sync %d\n", sync); | 
 | 249 | 	} | 
 | 250 | #endif | 
 | 251 |  | 
 | 252 | 	req->reply_expected = 1; | 
 | 253 | 	 | 
 | 254 | 	i = maciisi_write(req); | 
 | 255 | 	if (i) | 
 | 256 | 	{ | 
 | 257 | 		/* Normally, if a packet requires syncing, that happens at the end of | 
 | 258 | 		 * maciisi_send_request. But if the transfer fails, it will be restarted | 
 | 259 | 		 * by maciisi_interrupt(). We use need_sync to tell maciisi_interrupt | 
 | 260 | 		 * when to sync a packet that it sends out. | 
 | 261 | 		 *  | 
 | 262 | 		 * Suggestions on a better way to do this are welcome. | 
 | 263 | 		 */ | 
 | 264 | 		if(i == -EBUSY && sync) | 
 | 265 | 			need_sync = 1; | 
 | 266 | 		else | 
 | 267 | 			need_sync = 0; | 
 | 268 | 		return i; | 
 | 269 | 	} | 
 | 270 | 	if(sync) | 
 | 271 | 		maciisi_sync(req); | 
 | 272 | 	 | 
 | 273 | 	return 0; | 
 | 274 | } | 
 | 275 |  | 
 | 276 | /* Poll the ADB chip until the request completes */ | 
 | 277 | static void maciisi_sync(struct adb_request *req) | 
 | 278 | { | 
 | 279 | 	int count = 0;  | 
 | 280 |  | 
 | 281 | #ifdef DEBUG_MACIISI_ADB | 
 | 282 | 	printk(KERN_DEBUG "maciisi_sync called\n"); | 
 | 283 | #endif | 
 | 284 |  | 
 | 285 | 	/* If for some reason the ADB chip shuts up on us, we want to avoid an endless loop. */ | 
 | 286 | 	while (!req->complete && count++ < 50) { | 
 | 287 | 		maciisi_poll(); | 
 | 288 | 	} | 
 | 289 | 	/* This could be BAD... when the ADB controller doesn't respond | 
 | 290 | 	 * for this long, it's probably not coming back :-( */ | 
 | 291 | 	if(count >= 50) /* Hopefully shouldn't happen */ | 
 | 292 | 		printk(KERN_ERR "maciisi_send_request: poll timed out!\n"); | 
 | 293 | } | 
 | 294 |  | 
| Al Viro | 3272244 | 2006-01-12 01:06:13 -0800 | [diff] [blame] | 295 | int | 
 | 296 | maciisi_request(struct adb_request *req, void (*done)(struct adb_request *), | 
 | 297 | 	    int nbytes, ...) | 
 | 298 | { | 
 | 299 | 	va_list list; | 
 | 300 | 	int i; | 
 | 301 |  | 
 | 302 | 	req->nbytes = nbytes; | 
 | 303 | 	req->done = done; | 
 | 304 | 	req->reply_expected = 0; | 
 | 305 | 	va_start(list, nbytes); | 
 | 306 | 	for (i = 0; i < nbytes; i++) | 
 | 307 | 		req->data[i++] = va_arg(list, int); | 
 | 308 | 	va_end(list); | 
 | 309 |  | 
 | 310 | 	return maciisi_send_request(req, 1); | 
 | 311 | } | 
 | 312 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 313 | /* Enqueue a request, and run the queue if possible */ | 
 | 314 | static int | 
 | 315 | maciisi_write(struct adb_request* req) | 
 | 316 | { | 
 | 317 | 	unsigned long flags; | 
 | 318 | 	int i; | 
 | 319 |  | 
 | 320 | 	/* We will accept CUDA packets - the VIA sends them to us, so | 
 | 321 |            it figures that we should be able to send them to it */ | 
 | 322 | 	if (req->nbytes < 2 || req->data[0] > CUDA_PACKET) { | 
 | 323 | 		printk(KERN_ERR "maciisi_write: packet too small or not an ADB or CUDA packet\n"); | 
 | 324 | 		req->complete = 1; | 
 | 325 | 		return -EINVAL; | 
 | 326 | 	} | 
| Al Viro | a5d361f | 2006-01-12 01:06:34 -0800 | [diff] [blame] | 327 | 	req->next = NULL; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 328 | 	req->sent = 0; | 
 | 329 | 	req->complete = 0; | 
 | 330 | 	req->reply_len = 0; | 
 | 331 | 	 | 
 | 332 | 	local_irq_save(flags); | 
 | 333 |  | 
 | 334 | 	if (current_req) { | 
 | 335 | 		last_req->next = req; | 
 | 336 | 		last_req = req; | 
 | 337 | 	} else { | 
 | 338 | 		current_req = req; | 
 | 339 | 		last_req = req; | 
 | 340 | 	} | 
 | 341 | 	if (maciisi_state == idle) | 
 | 342 | 	{ | 
 | 343 | 		i = maciisi_start(); | 
 | 344 | 		if(i != 0) | 
 | 345 | 		{ | 
 | 346 | 			local_irq_restore(flags); | 
 | 347 | 			return i; | 
 | 348 | 		} | 
 | 349 | 	} | 
 | 350 | 	else | 
 | 351 | 	{ | 
 | 352 | #ifdef DEBUG_MACIISI_ADB | 
 | 353 | 		printk(KERN_DEBUG "maciisi_write: would start, but state is %d\n", maciisi_state); | 
 | 354 | #endif | 
 | 355 | 		local_irq_restore(flags); | 
 | 356 | 		return -EBUSY; | 
 | 357 | 	} | 
 | 358 |  | 
 | 359 | 	local_irq_restore(flags); | 
 | 360 |  | 
 | 361 | 	return 0; | 
 | 362 | } | 
 | 363 |  | 
 | 364 | static int | 
 | 365 | maciisi_start(void) | 
 | 366 | { | 
 | 367 | 	struct adb_request* req; | 
 | 368 | 	int status; | 
 | 369 |  | 
 | 370 | #ifdef DEBUG_MACIISI_ADB | 
 | 371 | 	status = via[B] & (TIP | TREQ); | 
 | 372 |  | 
 | 373 | 	printk(KERN_DEBUG "maciisi_start called, state=%d, status=%x, ifr=%x\n", maciisi_state, status, via[IFR]); | 
 | 374 | #endif | 
 | 375 |  | 
 | 376 | 	if (maciisi_state != idle) { | 
 | 377 | 		/* shouldn't happen */ | 
 | 378 | 		printk(KERN_ERR "maciisi_start: maciisi_start called when driver busy!\n"); | 
 | 379 | 		return -EBUSY; | 
 | 380 | 	} | 
 | 381 |  | 
 | 382 | 	req = current_req; | 
 | 383 | 	if (req == NULL) | 
 | 384 | 		return -EINVAL; | 
 | 385 |  | 
 | 386 | 	status = via[B] & (TIP|TREQ); | 
 | 387 | 	if (!(status & TREQ)) { | 
 | 388 | #ifdef DEBUG_MACIISI_ADB | 
 | 389 | 		printk(KERN_DEBUG "maciisi_start: bus busy - aborting\n"); | 
 | 390 | #endif | 
 | 391 | 		return -EBUSY; | 
 | 392 | 	} | 
 | 393 |  | 
 | 394 | 	/* Okay, send */ | 
 | 395 | #ifdef DEBUG_MACIISI_ADB | 
 | 396 | 	printk(KERN_DEBUG "maciisi_start: sending\n"); | 
 | 397 | #endif | 
 | 398 | 	/* Set state to active */ | 
 | 399 | 	via[B] |= TIP; | 
 | 400 | 	/* ACK off */ | 
 | 401 | 	via[B] &= ~TACK; | 
 | 402 | 	/* Delay */ | 
 | 403 | 	udelay(ADB_DELAY); | 
 | 404 | 	/* Shift out and send */ | 
 | 405 | 	via[ACR] |= SR_OUT; | 
 | 406 | 	via[SR] = req->data[0]; | 
 | 407 | 	data_index = 1; | 
 | 408 | 	/* ACK on */ | 
 | 409 | 	via[B] |= TACK; | 
 | 410 | 	maciisi_state = sending; | 
 | 411 |  | 
 | 412 | 	return 0; | 
 | 413 | } | 
 | 414 |  | 
 | 415 | void | 
 | 416 | maciisi_poll(void) | 
 | 417 | { | 
 | 418 | 	unsigned long flags; | 
 | 419 |  | 
 | 420 | 	local_irq_save(flags); | 
 | 421 | 	if (via[IFR] & SR_INT) { | 
| Al Viro | 2850bc2 | 2006-10-07 14:16:45 +0100 | [diff] [blame] | 422 | 		maciisi_interrupt(0, NULL); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 423 | 	} | 
 | 424 | 	else /* avoid calling this function too quickly in a loop */ | 
 | 425 | 		udelay(ADB_DELAY); | 
 | 426 |  | 
 | 427 | 	local_irq_restore(flags); | 
 | 428 | } | 
 | 429 |  | 
 | 430 | /* Shift register interrupt - this is *supposed* to mean that the | 
 | 431 |    register is either full or empty. In practice, I have no idea what | 
 | 432 |    it means :( */ | 
 | 433 | static irqreturn_t | 
| David Howells | 7d12e78 | 2006-10-05 14:55:46 +0100 | [diff] [blame] | 434 | maciisi_interrupt(int irq, void* arg) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 435 | { | 
 | 436 | 	int status; | 
 | 437 | 	struct adb_request *req; | 
 | 438 | #ifdef DEBUG_MACIISI_ADB | 
 | 439 | 	static int dump_reply = 0; | 
 | 440 | #endif | 
 | 441 | 	int i; | 
 | 442 | 	unsigned long flags; | 
 | 443 |  | 
 | 444 | 	local_irq_save(flags); | 
 | 445 |  | 
 | 446 | 	status = via[B] & (TIP|TREQ); | 
 | 447 | #ifdef DEBUG_MACIISI_ADB | 
 | 448 | 	printk(KERN_DEBUG "state %d status %x ifr %x\n", maciisi_state, status, via[IFR]); | 
 | 449 | #endif | 
 | 450 |  | 
 | 451 | 	if (!(via[IFR] & SR_INT)) { | 
 | 452 | 		/* Shouldn't happen, we hope */ | 
 | 453 | 		printk(KERN_ERR "maciisi_interrupt: called without interrupt flag set\n"); | 
 | 454 | 		local_irq_restore(flags); | 
 | 455 | 		return IRQ_NONE; | 
 | 456 | 	} | 
 | 457 |  | 
 | 458 | 	/* Clear the interrupt */ | 
 | 459 | 	/* via[IFR] = SR_INT; */ | 
 | 460 |  | 
 | 461 |  switch_start: | 
 | 462 | 	switch (maciisi_state) { | 
 | 463 | 	case idle: | 
 | 464 | 		if (status & TIP) | 
 | 465 | 			printk(KERN_ERR "maciisi_interrupt: state is idle but TIP asserted!\n"); | 
 | 466 |  | 
 | 467 | 		if(!reading_reply) | 
 | 468 | 			udelay(ADB_DELAY); | 
 | 469 | 		/* Shift in */ | 
 | 470 | 		via[ACR] &= ~SR_OUT; | 
 | 471 |  		/* Signal start of frame */ | 
 | 472 | 		via[B] |= TIP; | 
 | 473 | 		/* Clear the interrupt (throw this value on the floor, it's useless) */ | 
 | 474 | 		tmp = via[SR]; | 
 | 475 | 		/* ACK adb chip, high-low */ | 
 | 476 | 		via[B] |= TACK; | 
 | 477 | 		udelay(ADB_DELAY); | 
 | 478 | 		via[B] &= ~TACK; | 
 | 479 | 		reply_len = 0; | 
 | 480 | 		maciisi_state = reading; | 
 | 481 | 		if (reading_reply) { | 
 | 482 | 			reply_ptr = current_req->reply; | 
 | 483 | 		} else { | 
 | 484 | 			reply_ptr = maciisi_rbuf; | 
 | 485 | 		} | 
 | 486 | 		break; | 
 | 487 |  | 
 | 488 | 	case sending: | 
 | 489 | 		/* via[SR]; */ | 
 | 490 | 		/* Set ACK off */ | 
 | 491 | 		via[B] &= ~TACK; | 
 | 492 | 		req = current_req; | 
 | 493 |  | 
 | 494 | 		if (!(status & TREQ)) { | 
 | 495 | 			/* collision */ | 
 | 496 | 			printk(KERN_ERR "maciisi_interrupt: send collision\n"); | 
 | 497 | 			/* Set idle and input */ | 
 | 498 | 			via[ACR] &= ~SR_OUT; | 
 | 499 | 			tmp = via[SR]; | 
 | 500 | 			via[B] &= ~TIP; | 
 | 501 | 			/* Must re-send */ | 
 | 502 | 			reading_reply = 0; | 
 | 503 | 			reply_len = 0; | 
 | 504 | 			maciisi_state = idle; | 
 | 505 | 			udelay(ADB_DELAY); | 
 | 506 | 			/* process this now, because the IFR has been cleared */ | 
 | 507 | 			goto switch_start; | 
 | 508 | 		} | 
 | 509 |  | 
 | 510 | 		udelay(ADB_DELAY); | 
 | 511 |  | 
 | 512 | 		if (data_index >= req->nbytes) { | 
 | 513 | 			/* Sent the whole packet, put the bus back in idle state */ | 
 | 514 | 			/* Shift in, we are about to read a reply (hopefully) */ | 
 | 515 | 			via[ACR] &= ~SR_OUT; | 
 | 516 | 			tmp = via[SR]; | 
 | 517 | 			/* End of frame */ | 
 | 518 | 			via[B] &= ~TIP; | 
 | 519 | 			req->sent = 1; | 
 | 520 | 			maciisi_state = idle; | 
 | 521 | 			if (req->reply_expected) { | 
 | 522 | 				/* Note: only set this once we've | 
 | 523 |                                    successfully sent the packet */ | 
 | 524 | 				reading_reply = 1; | 
 | 525 | 			} else { | 
 | 526 | 				current_req = req->next; | 
 | 527 | 				if (req->done) | 
 | 528 | 					(*req->done)(req); | 
 | 529 | 				/* Do any queued requests now */ | 
 | 530 | 				i = maciisi_start(); | 
 | 531 | 				if(i == 0 && need_sync) { | 
 | 532 | 					/* Packet needs to be synced */ | 
 | 533 | 					maciisi_sync(current_req); | 
 | 534 | 				} | 
 | 535 | 				if(i != -EBUSY) | 
 | 536 | 					need_sync = 0; | 
 | 537 | 			} | 
 | 538 | 		} else { | 
 | 539 | 			/* Sending more stuff */ | 
 | 540 | 			/* Shift out */ | 
 | 541 | 			via[ACR] |= SR_OUT; | 
 | 542 | 			/* Write */ | 
 | 543 | 			via[SR] = req->data[data_index++]; | 
 | 544 | 			/* Signal 'byte ready' */ | 
 | 545 | 			via[B] |= TACK; | 
 | 546 | 		} | 
 | 547 | 		break; | 
 | 548 |  | 
 | 549 | 	case reading: | 
 | 550 | 		/* Shift in */ | 
 | 551 | 		/* via[ACR] &= ~SR_OUT; */ /* Not in 2.2 */ | 
 | 552 | 		if (reply_len++ > 16) { | 
 | 553 | 			printk(KERN_ERR "maciisi_interrupt: reply too long, aborting read\n"); | 
 | 554 | 			via[B] |= TACK; | 
 | 555 | 			udelay(ADB_DELAY); | 
 | 556 | 			via[B] &= ~(TACK|TIP); | 
 | 557 | 			maciisi_state = idle; | 
 | 558 | 			i = maciisi_start(); | 
 | 559 | 			if(i == 0 && need_sync) { | 
 | 560 | 				/* Packet needs to be synced */ | 
 | 561 | 				maciisi_sync(current_req); | 
 | 562 | 			} | 
 | 563 | 			if(i != -EBUSY) | 
 | 564 | 				need_sync = 0; | 
 | 565 | 			break; | 
 | 566 | 		} | 
 | 567 | 		/* Read data */ | 
 | 568 | 		*reply_ptr++ = via[SR]; | 
 | 569 | 		status = via[B] & (TIP|TREQ); | 
 | 570 | 		/* ACK on/off */ | 
 | 571 | 		via[B] |= TACK; | 
 | 572 | 		udelay(ADB_DELAY); | 
 | 573 | 		via[B] &= ~TACK;	 | 
 | 574 | 		if (!(status & TREQ)) | 
 | 575 | 			break; /* more stuff to deal with */ | 
 | 576 | 		 | 
 | 577 | 		/* end of frame */ | 
 | 578 | 		via[B] &= ~TIP; | 
 | 579 | 		tmp = via[SR]; /* That's what happens in 2.2 */ | 
 | 580 | 		udelay(ADB_DELAY); /* Give controller time to recover */ | 
 | 581 |  | 
 | 582 | 		/* end of packet, deal with it */ | 
 | 583 | 		if (reading_reply) { | 
 | 584 | 			req = current_req; | 
 | 585 | 			req->reply_len = reply_ptr - req->reply; | 
 | 586 | 			if (req->data[0] == ADB_PACKET) { | 
 | 587 | 				/* Have to adjust the reply from ADB commands */ | 
 | 588 | 				if (req->reply_len <= 2 || (req->reply[1] & 2) != 0) { | 
 | 589 | 					/* the 0x2 bit indicates no response */ | 
 | 590 | 					req->reply_len = 0; | 
 | 591 | 				} else { | 
 | 592 | 					/* leave just the command and result bytes in the reply */ | 
 | 593 | 					req->reply_len -= 2; | 
 | 594 | 					memmove(req->reply, req->reply + 2, req->reply_len); | 
 | 595 | 				} | 
 | 596 | 			} | 
 | 597 | #ifdef DEBUG_MACIISI_ADB | 
 | 598 | 			if (dump_reply) { | 
 | 599 | 				int i; | 
 | 600 | 				printk(KERN_DEBUG "maciisi_interrupt: reply is "); | 
 | 601 | 				for (i = 0; i < req->reply_len; ++i) | 
 | 602 | 					printk(" %.2x", req->reply[i]); | 
 | 603 | 				printk("\n"); | 
 | 604 | 			} | 
 | 605 | #endif | 
 | 606 | 			req->complete = 1; | 
 | 607 | 			current_req = req->next; | 
 | 608 | 			if (req->done) | 
 | 609 | 				(*req->done)(req); | 
 | 610 | 			/* Obviously, we got it */ | 
 | 611 | 			reading_reply = 0; | 
 | 612 | 		} else { | 
| David Howells | 7d12e78 | 2006-10-05 14:55:46 +0100 | [diff] [blame] | 613 | 			maciisi_input(maciisi_rbuf, reply_ptr - maciisi_rbuf); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 614 | 		} | 
 | 615 | 		maciisi_state = idle; | 
 | 616 | 		status = via[B] & (TIP|TREQ); | 
 | 617 | 		if (!(status & TREQ)) { | 
 | 618 | 			/* Timeout?! More likely, another packet coming in already */ | 
 | 619 | #ifdef DEBUG_MACIISI_ADB | 
 | 620 | 			printk(KERN_DEBUG "extra data after packet: status %x ifr %x\n", | 
 | 621 | 			       status, via[IFR]); | 
 | 622 | #endif | 
 | 623 | #if 0 | 
 | 624 | 			udelay(ADB_DELAY); | 
 | 625 | 			via[B] |= TIP; | 
 | 626 |  | 
 | 627 | 			maciisi_state = reading; | 
 | 628 | 			reading_reply = 0; | 
 | 629 | 			reply_ptr = maciisi_rbuf; | 
 | 630 | #else | 
 | 631 | 			/* Process the packet now */ | 
 | 632 | 			reading_reply = 0; | 
 | 633 | 			goto switch_start; | 
 | 634 | #endif | 
 | 635 | 			/* We used to do this... but the controller might actually have data for us */ | 
 | 636 | 			/* maciisi_stfu(); */ | 
 | 637 | 		} | 
 | 638 | 		else { | 
 | 639 | 			/* Do any queued requests now if possible */ | 
 | 640 | 			i = maciisi_start(); | 
 | 641 | 			if(i == 0 && need_sync) { | 
 | 642 | 				/* Packet needs to be synced */ | 
 | 643 | 				maciisi_sync(current_req); | 
 | 644 | 			} | 
 | 645 | 			if(i != -EBUSY) | 
 | 646 | 				need_sync = 0; | 
 | 647 | 		} | 
 | 648 | 		break; | 
 | 649 |  | 
 | 650 | 	default: | 
 | 651 | 		printk("maciisi_interrupt: unknown maciisi_state %d?\n", maciisi_state); | 
 | 652 | 	} | 
 | 653 | 	local_irq_restore(flags); | 
 | 654 | 	return IRQ_HANDLED; | 
 | 655 | } | 
 | 656 |  | 
 | 657 | static void | 
| David Howells | 7d12e78 | 2006-10-05 14:55:46 +0100 | [diff] [blame] | 658 | maciisi_input(unsigned char *buf, int nb) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 659 | { | 
 | 660 | #ifdef DEBUG_MACIISI_ADB | 
 | 661 |     int i; | 
 | 662 | #endif | 
 | 663 |  | 
 | 664 |     switch (buf[0]) { | 
 | 665 |     case ADB_PACKET: | 
| David Howells | 7d12e78 | 2006-10-05 14:55:46 +0100 | [diff] [blame] | 666 | 	    adb_input(buf+2, nb-2, buf[1] & 0x40); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 667 | 	    break; | 
 | 668 |     default: | 
 | 669 | #ifdef DEBUG_MACIISI_ADB | 
 | 670 | 	    printk(KERN_DEBUG "data from IIsi ADB (%d bytes):", nb); | 
 | 671 | 	    for (i = 0; i < nb; ++i) | 
 | 672 | 		    printk(" %.2x", buf[i]); | 
 | 673 | 	    printk("\n"); | 
 | 674 | #endif | 
 | 675 | 	    break; | 
 | 676 |     } | 
 | 677 | } |