⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 via-maciisi.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Device driver for the IIsi-style ADB on some Mac LC and II-class machines * * Based on via-cuda.c and via-macii.c, as well as the original * adb-bus.c, which in turn is somewhat influenced by (but uses no * code from) the NetBSD HWDIRECT ADB code.  Original IIsi driver work * was done by Robert Thompson and integrated into the old style * driver by Michael Schmitz. * * Original sources (c) Alan Cox, Paul Mackerras, and others. * * Rewritten for Unified ADB by David Huggins-Daines <dhd@debian.org> *  * 7/13/2000- extensive changes by Andrew McPherson <andrew@macduff.dhs.org> * Works about 30% of the time now. */#include <linux/types.h>#include <linux/errno.h>#include <linux/kernel.h>#include <linux/adb.h>#include <linux/cuda.h>#include <linux/delay.h>#include <linux/interrupt.h>#include <asm/macintosh.h>#include <asm/macints.h>#include <asm/machw.h>#include <asm/mac_via.h>static volatile unsigned char *via;/* VIA registers - spaced 0x200 bytes apart - only the ones we actually use */#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 SR		(10*RS)		/* Shift register */#define ACR		(11*RS)		/* Auxiliary control register */#define IFR		(13*RS)		/* Interrupt flag register */#define IER		(14*RS)		/* Interrupt enable register *//* Bits in B data register: all active low */#define TREQ		0x08		/* Transfer request (input) */#define TACK		0x10		/* Transfer acknowledge (output) */#define TIP		0x20		/* Transfer in progress (output) */#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 */#define SR_DATA		0x08		/* Shift register data */#define SR_CLOCK	0x10		/* Shift register clock */#define ADB_DELAY 150#undef DEBUG_MACIISI_ADBstatic struct adb_request* current_req;static struct adb_request* last_req;static unsigned char maciisi_rbuf[16];static unsigned char *reply_ptr;static int data_index;static int reading_reply;static int reply_len;static int tmp;static int need_sync;static enum maciisi_state {    idle,    sending,    reading,} maciisi_state;static int maciisi_probe(void);static int maciisi_init(void);static int maciisi_send_request(struct adb_request* req, int sync);static void maciisi_sync(struct adb_request *req);static int maciisi_write(struct adb_request* req);static irqreturn_t maciisi_interrupt(int irq, void* arg);static void maciisi_input(unsigned char *buf, int nb);static int maciisi_init_via(void);static void maciisi_poll(void);static int maciisi_start(void);struct adb_driver via_maciisi_driver = {	"Mac IIsi",	maciisi_probe,	maciisi_init,	maciisi_send_request,	NULL, /* maciisi_adb_autopoll, */	maciisi_poll,	NULL /* maciisi_reset_adb_bus */};static intmaciisi_probe(void){	if (macintosh_config->adb_type != MAC_ADB_IISI)		return -ENODEV;	via = via1;	return 0;}static intmaciisi_init(void){	int err;	if (via == NULL)		return -ENODEV;	if ((err = maciisi_init_via())) {		printk(KERN_ERR "maciisi_init: maciisi_init_via() failed, code %d\n", err);		via = NULL;		return err;	}	if (request_irq(IRQ_MAC_ADB, maciisi_interrupt, IRQ_FLG_LOCK | IRQ_FLG_FAST, 			"ADB", maciisi_interrupt)) {		printk(KERN_ERR "maciisi_init: can't get irq %d\n", IRQ_MAC_ADB);		return -EAGAIN;	}	printk("adb: Mac IIsi driver v0.2 for Unified ADB.\n");	return 0;}/* Flush data from the ADB controller */static voidmaciisi_stfu(void){	int status = via[B] & (TIP|TREQ);	if (status & TREQ) {#ifdef DEBUG_MACIISI_ADB		printk (KERN_DEBUG "maciisi_stfu called with TREQ high!\n");#endif		return;	}		udelay(ADB_DELAY);	via[ACR] &= ~SR_OUT;	via[IER] = IER_CLR | SR_INT;	udelay(ADB_DELAY);	status = via[B] & (TIP|TREQ);	if (!(status & TREQ))	{		via[B] |= TIP;		while(1)		{			int poll_timeout = ADB_DELAY * 5;			/* Poll for SR interrupt */			while (!(via[IFR] & SR_INT) && poll_timeout-- > 0)				status = via[B] & (TIP|TREQ);			tmp = via[SR]; /* Clear shift register */#ifdef DEBUG_MACIISI_ADB			printk(KERN_DEBUG "maciisi_stfu: status %x timeout %d data %x\n",			       status, poll_timeout, tmp);#endif				if(via[B] & TREQ)				break;				/* ACK on-off */			via[B] |= TACK;			udelay(ADB_DELAY);			via[B] &= ~TACK;		}		/* end frame */		via[B] &= ~TIP;		udelay(ADB_DELAY);	}	via[IER] = IER_SET | SR_INT;	}/* All specifically VIA-related initialization goes here */static intmaciisi_init_via(void){	int	i;		/* Set the lines up. We want TREQ as input TACK|TIP as output */	via[DIRB] = (via[DIRB] | TACK | TIP) & ~TREQ;	/* Shift register on input */	via[ACR]  = (via[ACR] & ~SR_CTRL) | SR_EXT;#ifdef DEBUG_MACIISI_ADB	printk(KERN_DEBUG "maciisi_init_via: initial status %x\n", via[B] & (TIP|TREQ));#endif	/* Wipe any pending data and int */	tmp = via[SR];	/* Enable keyboard interrupts */	via[IER] = IER_SET | SR_INT;	/* Set initial state: idle */	via[B] &= ~(TACK|TIP);	/* Clear interrupt bit */	via[IFR] = SR_INT;	for(i = 0; i < 60; i++) {		udelay(ADB_DELAY);		maciisi_stfu();		udelay(ADB_DELAY);		if(via[B] & TREQ)			break;	}	if (i == 60)		printk(KERN_ERR "maciisi_init_via: bus jam?\n");	maciisi_state = idle;	need_sync = 0;	return 0;}/* Send a request, possibly waiting for a reply */static intmaciisi_send_request(struct adb_request* req, int sync){	int i;#ifdef DEBUG_MACIISI_ADB	static int dump_packet = 0;#endif	if (via == NULL) {		req->complete = 1;		return -ENXIO;	}#ifdef DEBUG_MACIISI_ADB	if (dump_packet) {		printk(KERN_DEBUG "maciisi_send_request:");		for (i = 0; i < req->nbytes; i++) {			printk(" %.2x", req->data[i]);		}		printk(" sync %d\n", sync);	}#endif	req->reply_expected = 1;		i = maciisi_write(req);	if (i)	{		/* Normally, if a packet requires syncing, that happens at the end of		 * maciisi_send_request. But if the transfer fails, it will be restarted		 * by maciisi_interrupt(). We use need_sync to tell maciisi_interrupt		 * when to sync a packet that it sends out.		 * 		 * Suggestions on a better way to do this are welcome.		 */		if(i == -EBUSY && sync)			need_sync = 1;		else			need_sync = 0;		return i;	}	if(sync)		maciisi_sync(req);		return 0;}/* Poll the ADB chip until the request completes */static void maciisi_sync(struct adb_request *req){	int count = 0; #ifdef DEBUG_MACIISI_ADB	printk(KERN_DEBUG "maciisi_sync called\n");#endif	/* If for some reason the ADB chip shuts up on us, we want to avoid an endless loop. */	while (!req->complete && count++ < 50) {		maciisi_poll();	}	/* This could be BAD... when the ADB controller doesn't respond	 * for this long, it's probably not coming back :-( */	if(count >= 50) /* Hopefully shouldn't happen */		printk(KERN_ERR "maciisi_send_request: poll timed out!\n");}intmaciisi_request(struct adb_request *req, void (*done)(struct adb_request *),	    int nbytes, ...){	va_list list;	int i;	req->nbytes = nbytes;	req->done = done;	req->reply_expected = 0;	va_start(list, nbytes);	for (i = 0; i < nbytes; i++)		req->data[i++] = va_arg(list, int);	va_end(list);	return maciisi_send_request(req, 1);}/* Enqueue a request, and run the queue if possible */static intmaciisi_write(struct adb_request* req){	unsigned long flags;	int i;	/* We will accept CUDA packets - the VIA sends them to us, so           it figures that we should be able to send them to it */	if (req->nbytes < 2 || req->data[0] > CUDA_PACKET) {		printk(KERN_ERR "maciisi_write: packet too small or not an ADB or CUDA packet\n");		req->complete = 1;		return -EINVAL;	}	req->next = NULL;	req->sent = 0;	req->complete = 0;	req->reply_len = 0;		local_irq_save(flags);	if (current_req) {		last_req->next = req;		last_req = req;	} else {		current_req = req;		last_req = req;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -