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

📄 via-pmu.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
		while (!req->complete)			pmu_poll();	return 0;}/* Enable/disable autopolling */static int __openfirmwarepmu_adb_autopoll(int devs){	struct adb_request req;	if ((vias == NULL) || (!pmu_fully_inited) || !pmu_has_adb)		return -ENXIO;	if (devs) {		adb_dev_map = devs;		pmu_request(&req, NULL, 5, PMU_ADB_CMD, 0, 0x86,			    adb_dev_map >> 8, adb_dev_map);		pmu_adb_flags = 2;	} else {		pmu_request(&req, NULL, 1, PMU_ADB_POLL_OFF);		pmu_adb_flags = 0;	}	while (!req.complete)		pmu_poll();	return 0;}/* Reset the ADB bus */static int __openfirmwarepmu_adb_reset_bus(void){	struct adb_request req;	int save_autopoll = adb_dev_map;	if ((vias == NULL) || (!pmu_fully_inited) || !pmu_has_adb)		return -ENXIO;	/* anyone got a better idea?? */	pmu_adb_autopoll(0);	req.nbytes = 5;	req.done = NULL;	req.data[0] = PMU_ADB_CMD;	req.data[1] = 0;	req.data[2] = ADB_BUSRESET; /* 3 ??? */	req.data[3] = 0;	req.data[4] = 0;	req.reply_len = 0;	req.reply_expected = 1;	if (pmu_queue_request(&req) != 0) {		printk(KERN_ERR "pmu_adb_reset_bus: pmu_queue_request failed\n");		return -EIO;	}	while (!req.complete)		pmu_poll();	if (save_autopoll != 0)		pmu_adb_autopoll(save_autopoll);	return 0;}#endif /* CONFIG_ADB *//* Construct and send a pmu request */int __openfirmwarepmu_request(struct adb_request *req, void (*done)(struct adb_request *),	    int nbytes, ...){	va_list list;	int i;	if (vias == NULL)		return -ENXIO;	if (nbytes < 0 || nbytes > 32) {		printk(KERN_ERR "pmu_request: bad nbytes (%d)\n", nbytes);		req->complete = 1;		return -EINVAL;	}	req->nbytes = nbytes;	req->done = done;	va_start(list, nbytes);	for (i = 0; i < nbytes; ++i)		req->data[i] = va_arg(list, int);	va_end(list);	if (pmu_data_len[req->data[0]][1] != 0) {		req->reply[0] = ADB_RET_OK;		req->reply_len = 1;	} else		req->reply_len = 0;	req->reply_expected = 0;	return pmu_queue_request(req);}int __openfirmwarepmu_queue_request(struct adb_request *req){	unsigned long flags;	int nsend;	if (via == NULL) {		req->complete = 1;		return -ENXIO;	}	if (req->nbytes <= 0) {		req->complete = 1;		return 0;	}	nsend = pmu_data_len[req->data[0]][0];	if (nsend >= 0 && req->nbytes != nsend + 1) {		req->complete = 1;		return -EINVAL;	}	req->next = 0;	req->sent = 0;	req->complete = 0;	spin_lock_irqsave(&pmu_lock, flags);	if (current_req != 0) {		last_req->next = req;		last_req = req;	} else {		current_req = req;		last_req = req;		if (pmu_state == idle)			pmu_start();	}	spin_unlock_irqrestore(&pmu_lock, flags);	return 0;}static void __openfirmwarewait_for_ack(void){	/* Sightly increased the delay, I had one occurence of the message	 * reported	 */	int timeout = 4000;	while ((in_8(&via[B]) & TACK) == 0) {		if (--timeout < 0) {			printk(KERN_ERR "PMU not responding (!ack)\n");			return;		}		udelay(10);	}}/* New PMU seems to be very sensitive to those timings, so we make sure * PCI is flushed immediately */static void __openfirmwaresend_byte(int x){	volatile unsigned char *v = via;	out_8(&v[ACR], in_8(&v[ACR]) | SR_OUT | SR_EXT);	out_8(&v[SR], x);	out_8(&v[B], in_8(&v[B]) & ~TREQ);		/* assert TREQ */	(void)in_8(&v[B]);}static void __openfirmwarerecv_byte(){	volatile unsigned char *v = via;	out_8(&v[ACR], (in_8(&v[ACR]) & ~SR_OUT) | SR_EXT);	in_8(&v[SR]);		/* resets SR */	out_8(&v[B], in_8(&v[B]) & ~TREQ);	(void)in_8(&v[B]);}static volatile int disable_poll;static void __openfirmwarepmu_start(){	struct adb_request *req;	/* assert pmu_state == idle */	/* get the packet to send */	req = current_req;	if (req == 0 || pmu_state != idle	    || (/*req->reply_expected && */req_awaiting_reply))		return;	pmu_state = sending;	data_index = 1;	data_len = pmu_data_len[req->data[0]][0];	/* Sounds safer to make sure ACK is high before writing. This helped	 * kill a problem with ADB and some iBooks	 */	wait_for_ack();	/* set the shift register to shift out and send a byte */	send_byte(req->data[0]);}void __openfirmwarepmu_poll(){	if (!via)		return;	if (disable_poll)		return;	/* Kicks ADB read when PMU is suspended */	if (pmu_suspended)		adb_int_pending = 1;	do {		via_pmu_interrupt(0, 0, 0);	} while (pmu_suspended && (adb_int_pending || pmu_state != idle		|| req_awaiting_reply));}/* This function loops until the PMU is idle and prevents it from * anwsering to ADB interrupts. pmu_request can still be called. * This is done to avoid spurrious shutdowns when we know we'll have * interrupts switched off for a long time */void __openfirmwarepmu_suspend(void){	unsigned long flags;#ifdef SUSPEND_USES_PMU	struct adb_request *req;#endif	if (!via)		return;		spin_lock_irqsave(&pmu_lock, flags);	pmu_suspended++;	if (pmu_suspended > 1) {		spin_unlock_irqrestore(&pmu_lock, flags);		return;	}	do {		spin_unlock(&pmu_lock);		via_pmu_interrupt(0, 0, 0);		spin_lock(&pmu_lock);		if (!adb_int_pending && pmu_state == idle && !req_awaiting_reply) {#ifdef SUSPEND_USES_PMU			pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0);			spin_unlock_irqrestore(&pmu_lock, flags);			while(!req.complete)				pmu_poll();#else /* SUSPEND_USES_PMU */			if (gpio_irq >= 0)				disable_irq(gpio_irq);			out_8(&via[IER], CB1_INT | IER_CLR);			spin_unlock_irqrestore(&pmu_lock, flags);#endif /* SUSPEND_USES_PMU */			break;		}	} while (1);}void __openfirmwarepmu_resume(void){	unsigned long flags;	if (!via || (pmu_suspended < 1))		return;	spin_lock_irqsave(&pmu_lock, flags);	pmu_suspended--;	if (pmu_suspended > 0) {		spin_unlock_irqrestore(&pmu_lock, flags);		return;	}	adb_int_pending = 1;#ifdef SUSPEND_USES_PMU	pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0xfc);	spin_unlock_irqrestore(&pmu_lock, flags);	while(!req.complete)		pmu_poll();#else /* SUSPEND_USES_PMU */	if (gpio_irq >= 0)		enable_irq(gpio_irq);	out_8(&via[IER], CB1_INT | IER_SET);	spin_unlock_irqrestore(&pmu_lock, flags);	pmu_poll();#endif /* SUSPEND_USES_PMU */}static void __openfirmwarevia_pmu_interrupt(int irq, void *arg, struct pt_regs *regs){	unsigned long flags;	int intr;	int nloop = 0;	/* This is a bit brutal, we can probably do better */	spin_lock_irqsave(&pmu_lock, flags);	++disable_poll;			while ((intr = in_8(&via[IFR])) != 0) {		if (++nloop > 1000) {			printk(KERN_DEBUG "PMU: stuck in intr loop, "			       "intr=%x pmu_state=%d\n", intr, pmu_state);			break;		}		if (intr & SR_INT)			pmu_sr_intr(regs);		else if (intr & CB1_INT) {			adb_int_pending = 1;			out_8(&via[IFR], CB1_INT);		}		intr &= ~(SR_INT | CB1_INT);		if (intr != 0) {			out_8(&via[IFR], intr);		}	}	/* This is not necessary except if synchronous ADB requests are done	 * with interrupts off, which should not happen. Since I'm not sure	 * this "wiring" will remain, I'm commenting it out for now. Please do	 * not remove. -- BenH.	 */#if 0	if (gpio_reg && !pmu_suspended && (in_8(gpio_reg + 0x9) & 0x02) == 0)		adb_int_pending = 1;#endif	if (pmu_state == idle) {		if (adb_int_pending) {			pmu_state = intack;			/* Sounds safer to make sure ACK is high before writing.			 * This helped kill a problem with ADB and some iBooks			 */			wait_for_ack();			send_byte(PMU_INT_ACK);			adb_int_pending = 0;		} else if (current_req) {			pmu_start();		}	}		--disable_poll;	spin_unlock_irqrestore(&pmu_lock, flags);}static void __openfirmwaregpio1_interrupt(int irq, void *arg, struct pt_regs *regs){	adb_int_pending = 1;	via_pmu_interrupt(0, 0, 0);}static void __openfirmwarepmu_sr_intr(struct pt_regs *regs){	struct adb_request *req;	int bite;	if (via[B] & TREQ) {		printk(KERN_ERR "PMU: spurious SR intr (%x)\n", via[B]);		out_8(&via[IFR], SR_INT);		return;	}	/* This one seems to appear with PMU99. According to OF methods,	 * the protocol didn't change...	 */	if (via[B] & TACK) {		while ((in_8(&via[B]) & TACK) != 0)			;	}	/* reset TREQ and wait for TACK to go high */	out_8(&via[B], in_8(&via[B]) | TREQ);	wait_for_ack();	/* if reading grab the byte, and reset the interrupt */	if (pmu_state == reading || pmu_state == reading_intr)		bite = in_8(&via[SR]);	out_8(&via[IFR], SR_INT);	switch (pmu_state) {	case sending:		req = current_req;		if (data_len < 0) {			data_len = req->nbytes - 1;			send_byte(data_len);			break;		}		if (data_index <= data_len) {			send_byte(req->data[data_index++]);			break;		}		req->sent = 1;		data_len = pmu_data_len[req->data[0]][1];		if (data_len == 0) {			pmu_state = idle;			current_req = req->next;			if (req->reply_expected)				req_awaiting_reply = req;			else {				spin_unlock(&pmu_lock);				pmu_done(req);				spin_lock(&pmu_lock);			}		} else {			pmu_state = reading;			data_index = 0;			reply_ptr = req->reply + req->reply_len;			recv_byte();		}		break;	case intack:		data_index = 0;		data_len = -1;		pmu_state = reading_intr;		reply_ptr = interrupt_data;		recv_byte();		break;	case reading:	case reading_intr:		if (data_len == -1) {			data_len = bite;			if (bite > 32)				printk(KERN_ERR "PMU: bad reply len %d\n",				       bite);		} else {			reply_ptr[data_index++] = bite;		}		if (data_index < data_len) {			recv_byte();			break;		}		if (pmu_state == reading_intr) {			spin_unlock(&pmu_lock);			pmu_handle_data(interrupt_data, data_index, regs);			spin_lock(&pmu_lock);		} else {			req = current_req;			current_req = req->next;			req->reply_len += data_index;			spin_unlock(&pmu_lock);			pmu_done(req);			spin_lock(&pmu_lock);		}		pmu_state = idle;		break;	default:		printk(KERN_ERR "via_pmu_interrupt: unknown state %d?\n",		       pmu_state);	}}static void __openfirmwarepmu_done(struct adb_request *req){	req->complete = 1;	if (req->done)		(*req->done)(req);}/* Interrupt data could be the result data from an ADB cmd */static void __openfirmwarepmu_handle_data(unsigned char *data, int len, struct pt_regs *regs){	asleep = 0;	if (len < 1) {//		xmon_printk("empty ADB\n");		adb_int_pending = 0;		return;	}	if (data[0] & PMU_INT_ADB) {		if ((data[0] & PMU_INT_ADB_AUTO) == 0) {			struct adb_request *req = req_awaiting_reply;			if (req == 0) {				printk(KERN_ERR "PMU: extra ADB reply\n");				return;			}			req_awaiting_reply = 0;			if (len <= 2)				req->reply_len = 0;			else {				memcpy(req->reply, data + 1, len - 1);				req->reply_len = len - 1;			}			pmu_done(req);

⌨️ 快捷键说明

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