Пример #1
0
/* Shift register interrupt - this is *supposed* to mean that the
   register is either full or empty. In practice, I have no idea what
   it means :( */
static irqreturn_t
maciisi_interrupt(int irq, void* arg)
{
    int status;
    struct adb_request *req;
#ifdef DEBUG_MACIISI_ADB
    static int dump_reply = 0;
#endif
    int i;
    unsigned long flags;

    local_irq_save(flags);

    status = via[B] & (TIP|TREQ);
#ifdef DEBUG_MACIISI_ADB
    printk(KERN_DEBUG "state %d status %x ifr %x\n", maciisi_state, status, via[IFR]);
#endif

    if (!(via[IFR] & SR_INT)) {
        /* Shouldn't happen, we hope */
        printk(KERN_ERR "maciisi_interrupt: called without interrupt flag set\n");
        local_irq_restore(flags);
        return IRQ_NONE;
    }

    /* Clear the interrupt */
    /* via[IFR] = SR_INT; */

 switch_start:
    switch (maciisi_state) {
    case idle:
        if (status & TIP)
            printk(KERN_ERR "maciisi_interrupt: state is idle but TIP asserted!\n");

        if(!reading_reply)
            udelay(ADB_DELAY);
        /* Shift in */
        via[ACR] &= ~SR_OUT;
         /* Signal start of frame */
        via[B] |= TIP;
        /* Clear the interrupt (throw this value on the floor, it's useless) */
        tmp = via[SR];
        /* ACK adb chip, high-low */
        via[B] |= TACK;
        udelay(ADB_DELAY);
        via[B] &= ~TACK;
        reply_len = 0;
        maciisi_state = reading;
        if (reading_reply) {
            reply_ptr = current_req->reply;
        } else {
            reply_ptr = maciisi_rbuf;
        }
        break;

    case sending:
        /* via[SR]; */
        /* Set ACK off */
        via[B] &= ~TACK;
        req = current_req;

        if (!(status & TREQ)) {
            /* collision */
            printk(KERN_ERR "maciisi_interrupt: send collision\n");
            /* Set idle and input */
            via[ACR] &= ~SR_OUT;
            tmp = via[SR];
            via[B] &= ~TIP;
            /* Must re-send */
            reading_reply = 0;
            reply_len = 0;
            maciisi_state = idle;
            udelay(ADB_DELAY);
            /* process this now, because the IFR has been cleared */
            goto switch_start;
        }

        udelay(ADB_DELAY);

        if (data_index >= req->nbytes) {
            /* Sent the whole packet, put the bus back in idle state */
            /* Shift in, we are about to read a reply (hopefully) */
            via[ACR] &= ~SR_OUT;
            tmp = via[SR];
            /* End of frame */
            via[B] &= ~TIP;
            req->sent = 1;
            maciisi_state = idle;
            if (req->reply_expected) {
                /* Note: only set this once we've
                                   successfully sent the packet */
                reading_reply = 1;
            } else {
                current_req = req->next;
                if (req->done)
                    (*req->done)(req);
                /* Do any queued requests now */
                i = maciisi_start();
                if(i == 0 && need_sync) {
                    /* Packet needs to be synced */
                    maciisi_sync(current_req);
                }
                if(i != -EBUSY)
                    need_sync = 0;
            }
        } else {
            /* Sending more stuff */
            /* Shift out */
            via[ACR] |= SR_OUT;
            /* Write */
            via[SR] = req->data[data_index++];
            /* Signal 'byte ready' */
            via[B] |= TACK;
        }
        break;

    case reading:
        /* Shift in */
        /* via[ACR] &= ~SR_OUT; */ /* Not in 2.2 */
        if (reply_len++ > 16) {
            printk(KERN_ERR "maciisi_interrupt: reply too long, aborting read\n");
            via[B] |= TACK;
            udelay(ADB_DELAY);
            via[B] &= ~(TACK|TIP);
            maciisi_state = idle;
            i = maciisi_start();
            if(i == 0 && need_sync) {
                /* Packet needs to be synced */
                maciisi_sync(current_req);
            }
            if(i != -EBUSY)
                need_sync = 0;
            break;
        }
        /* Read data */
        *reply_ptr++ = via[SR];
        status = via[B] & (TIP|TREQ);
        /* ACK on/off */
        via[B] |= TACK;
        udelay(ADB_DELAY);
        via[B] &= ~TACK;    
        if (!(status & TREQ))
            break; /* more stuff to deal with */
        
        /* end of frame */
        via[B] &= ~TIP;
        tmp = via[SR]; /* That's what happens in 2.2 */
        udelay(ADB_DELAY); /* Give controller time to recover */

        /* end of packet, deal with it */
        if (reading_reply) {
            req = current_req;
            req->reply_len = reply_ptr - req->reply;
            if (req->data[0] == ADB_PACKET) {
                /* Have to adjust the reply from ADB commands */
                if (req->reply_len <= 2 || (req->reply[1] & 2) != 0) {
                    /* the 0x2 bit indicates no response */
                    req->reply_len = 0;
                } else {
                    /* leave just the command and result bytes in the reply */
                    req->reply_len -= 2;
                    memmove(req->reply, req->reply + 2, req->reply_len);
                }
            }
#ifdef DEBUG_MACIISI_ADB
            if (dump_reply) {
                int i;
                printk(KERN_DEBUG "maciisi_interrupt: reply is ");
                for (i = 0; i < req->reply_len; ++i)
                    printk(" %.2x", req->reply[i]);
                printk("\n");
            }
#endif
            req->complete = 1;
            current_req = req->next;
            if (req->done)
                (*req->done)(req);
            /* Obviously, we got it */
            reading_reply = 0;
        } else {
            maciisi_input(maciisi_rbuf, reply_ptr - maciisi_rbuf);
        }
        maciisi_state = idle;
        status = via[B] & (TIP|TREQ);
        if (!(status & TREQ)) {
            /* Timeout?! More likely, another packet coming in already */
#ifdef DEBUG_MACIISI_ADB
            printk(KERN_DEBUG "extra data after packet: status %x ifr %x\n",
                   status, via[IFR]);
#endif
#if 0
            udelay(ADB_DELAY);
            via[B] |= TIP;

            maciisi_state = reading;
            reading_reply = 0;
            reply_ptr = maciisi_rbuf;
#else
            /* Process the packet now */
            reading_reply = 0;
            goto switch_start;
#endif
            /* We used to do this... but the controller might actually have data for us */
            /* maciisi_stfu(); */
        }
        else {
            /* Do any queued requests now if possible */
            i = maciisi_start();
            if(i == 0 && need_sync) {
                /* Packet needs to be synced */
                maciisi_sync(current_req);
            }
            if(i != -EBUSY)
                need_sync = 0;
        }
        break;

    default:
        printk("maciisi_interrupt: unknown maciisi_state %d?\n", maciisi_state);
    }
    local_irq_restore(flags);
    return IRQ_HANDLED;
}
Пример #2
0
/* Shift register interrupt - this is *supposed* to mean that the
   register is either full or empty. In practice, I have no idea what
   it means :( */
static void
maciisi_interrupt(int irq, void* arg, struct pt_regs* regs)
{
	int status;
	struct adb_request *req;
	static int dump_reply = 1;

	if (!(via[IFR] & SR_INT)) {
		/* Shouldn't happen, we hope */
		printk(KERN_DEBUG "maciisi_interrupt: called without interrupt flag set\n");
		return;
	}

	status = via[B] & (TIP|TREQ);
	printk(KERN_DEBUG "state %d status %x ifr %x\n", maciisi_state, status, via[IFR]);

 switch_start:
	switch (maciisi_state) {
	case idle:
		printk(KERN_DEBUG "maciisi_interrupt: state=idle, status %x\n", status);
		if (status & TIP)
			printk(KERN_DEBUG "maciisi_interrupt: state is idle but TIP asserted!\n");

		udelay(ADB_DELAY);
		/* Shift in */
		via[ACR] &= ~SR_OUT;
 		/* Signal start of frame */
		via[B] |= TIP;
		/* Clear the interrupt (throw this value on the floor, it's useless) */
		via[SR];
		/* ACK adb chip, high-low */
		via[B] |= TACK;
		udelay(ADB_DELAY);
		via[B] &= ~TACK;
		reply_len = 0;
		maciisi_state = reading;
		if (reading_reply) {
			reply_ptr = current_req->reply;
		} else {
			printk(KERN_DEBUG "maciisi_interrupt: received unsolicited packet\n");
			reply_ptr = maciisi_rbuf;
		}
		break;

	case sending:
		printk(KERN_DEBUG "maciisi_interrupt: state=sending, status=%x\n", status);
		/* Clear interrupt */
		via[SR];
		/* Set ACK off */
		via[B] &= ~TACK;
		req = current_req;

		if (!(status & TREQ)) {
			/* collision */
			printk(KERN_DEBUG "maciisi_interrupt: send collision\n");
			/* Set idle and input */
			via[B] &= ~TIP;
			via[ACR] &= ~SR_OUT;
			/* Must re-send */
			reading_reply = 0;
			reply_len = 0;
			maciisi_state = idle;
			/* process this now, because the IFR has been cleared */
			goto switch_start;
		}

		if (data_index >= req->nbytes) {
			/* Sent the whole packet, put the bus back in idle state */
			/* Shift in, we are about to read a reply (hopefully) */
			via[ACR] &= ~SR_OUT;
			/* End of frame */
			via[B] &= ~TIP;
			req->sent = 1;
			maciisi_state = idle;
			if (req->reply_expected) {
				/* Note: only set this once we've
                                   successfully sent the packet */
				reading_reply = 1;
			} else {
				current_req = req->next;
				if (req->done)
					(*req->done)(req);
			}
		} else {
			/* Sending more stuff */
			/* Shift out */
			via[ACR] |= SR_OUT;
			/* Delay */
			udelay(ADB_DELAY);
			/* Write */
			via[SR] = req->data[data_index++];
			/* Signal 'byte ready' */
			via[B] |= TACK;
		}
		break;

	case reading:
		printk(KERN_DEBUG "maciisi_interrupt: state=reading, status=%x\n", status);
		/* Shift in */
		via[ACR] &= ~SR_OUT;
		if (reply_len++ > 16) {
			printk(KERN_ERR "maciisi_interrupt: reply too long, aborting read\n");
			via[B] |= TACK;
			udelay(ADB_DELAY);
			via[B] &= ~(TACK|TIP);
			maciisi_state = idle;
			maciisi_start();
			break;
		}
		*reply_ptr++ = via[SR];
		status = via[B] & (TIP|TREQ);
		/* ACK on/off */
		via[B] |= TACK;
		udelay(ADB_DELAY);
		via[B] &= ~TACK;	
		if (!(status & TREQ))
			break; /* more stuff to deal with */
		
		/* end of frame */
		via[B] &= ~TIP;

		/* end of packet, deal with it */
		if (reading_reply) {
			req = current_req;
			req->reply_len = reply_ptr - req->reply;
			if (req->data[0] == ADB_PACKET) {
				/* Have to adjust the reply from ADB commands */
				if (req->reply_len <= 2 || (req->reply[1] & 2) != 0) {
					/* the 0x2 bit indicates no response */
					req->reply_len = 0;
				} else {
					/* leave just the command and result bytes in the reply */
					req->reply_len -= 2;
					memmove(req->reply, req->reply + 2, req->reply_len);
				}
			}
			if (dump_reply) {
				int i;
				printk(KERN_DEBUG "maciisi_interrupt: reply is ");
				for (i = 0; i < req->reply_len; ++i)
					printk(" %.2x", req->reply[i]);
				printk("\n");
			}
			req->complete = 1;
			current_req = req->next;
			if (req->done)
				(*req->done)(req);
			/* Obviously, we got it */
			reading_reply = 0;
		} else {
			maciisi_input(maciisi_rbuf, reply_ptr - maciisi_rbuf, regs);
		}
		maciisi_state = idle;
		status = via[B] & (TIP|TREQ);
		if (!(status & TREQ)) {
			/* Timeout?! */
			printk(KERN_DEBUG "extra data after packet: status %x ifr %x\n",
			       status, via[IFR]);
			maciisi_stfu();
		}
		/* Do any queued requests now if possible */
		maciisi_start();
		break;

	default:
		printk("maciisi_interrupt: unknown maciisi_state %d?\n", maciisi_state);
	}
}
static irqreturn_t
maciisi_interrupt(int irq, void* arg)
{
	int status;
	struct adb_request *req;
#ifdef DEBUG_MACIISI_ADB
	static int dump_reply = 0;
#endif
	int i;
	unsigned long flags;

	local_irq_save(flags);

	status = via[B] & (TIP|TREQ);
#ifdef DEBUG_MACIISI_ADB
	printk(KERN_DEBUG "state %d status %x ifr %x\n", maciisi_state, status, via[IFR]);
#endif

	if (!(via[IFR] & SR_INT)) {
		
		printk(KERN_ERR "maciisi_interrupt: called without interrupt flag set\n");
		local_irq_restore(flags);
		return IRQ_NONE;
	}

	
	

 switch_start:
	switch (maciisi_state) {
	case idle:
		if (status & TIP)
			printk(KERN_ERR "maciisi_interrupt: state is idle but TIP asserted!\n");

		if(!reading_reply)
			udelay(ADB_DELAY);
		
		via[ACR] &= ~SR_OUT;
 		
		via[B] |= TIP;
		
		tmp = via[SR];
		
		via[B] |= TACK;
		udelay(ADB_DELAY);
		via[B] &= ~TACK;
		reply_len = 0;
		maciisi_state = reading;
		if (reading_reply) {
			reply_ptr = current_req->reply;
		} else {
			reply_ptr = maciisi_rbuf;
		}
		break;

	case sending:
		
		
		via[B] &= ~TACK;
		req = current_req;

		if (!(status & TREQ)) {
			
			printk(KERN_ERR "maciisi_interrupt: send collision\n");
			
			via[ACR] &= ~SR_OUT;
			tmp = via[SR];
			via[B] &= ~TIP;
			
			reading_reply = 0;
			reply_len = 0;
			maciisi_state = idle;
			udelay(ADB_DELAY);
			
			goto switch_start;
		}

		udelay(ADB_DELAY);

		if (data_index >= req->nbytes) {
			
			
			via[ACR] &= ~SR_OUT;
			tmp = via[SR];
			
			via[B] &= ~TIP;
			req->sent = 1;
			maciisi_state = idle;
			if (req->reply_expected) {
				reading_reply = 1;
			} else {
				current_req = req->next;
				if (req->done)
					(*req->done)(req);
				
				i = maciisi_start();
				if(i == 0 && need_sync) {
					
					maciisi_sync(current_req);
				}
				if(i != -EBUSY)
					need_sync = 0;
			}
		} else {
			
			
			via[ACR] |= SR_OUT;
			
			via[SR] = req->data[data_index++];
			
			via[B] |= TACK;
		}
		break;

	case reading:
		
		 
		if (reply_len++ > 16) {
			printk(KERN_ERR "maciisi_interrupt: reply too long, aborting read\n");
			via[B] |= TACK;
			udelay(ADB_DELAY);
			via[B] &= ~(TACK|TIP);
			maciisi_state = idle;
			i = maciisi_start();
			if(i == 0 && need_sync) {
				
				maciisi_sync(current_req);
			}
			if(i != -EBUSY)
				need_sync = 0;
			break;
		}
		
		*reply_ptr++ = via[SR];
		status = via[B] & (TIP|TREQ);
		
		via[B] |= TACK;
		udelay(ADB_DELAY);
		via[B] &= ~TACK;	
		if (!(status & TREQ))
			break; 
		
		
		via[B] &= ~TIP;
		tmp = via[SR]; 
		udelay(ADB_DELAY); 

		
		if (reading_reply) {
			req = current_req;
			req->reply_len = reply_ptr - req->reply;
			if (req->data[0] == ADB_PACKET) {
				
				if (req->reply_len <= 2 || (req->reply[1] & 2) != 0) {
					
					req->reply_len = 0;
				} else {
					
					req->reply_len -= 2;
					memmove(req->reply, req->reply + 2, req->reply_len);
				}
			}
#ifdef DEBUG_MACIISI_ADB
			if (dump_reply) {
				int i;
				printk(KERN_DEBUG "maciisi_interrupt: reply is ");
				for (i = 0; i < req->reply_len; ++i)
					printk(" %.2x", req->reply[i]);
				printk("\n");
			}
#endif
			req->complete = 1;
			current_req = req->next;
			if (req->done)
				(*req->done)(req);
			
			reading_reply = 0;
		} else {
			maciisi_input(maciisi_rbuf, reply_ptr - maciisi_rbuf);
		}
		maciisi_state = idle;
		status = via[B] & (TIP|TREQ);
		if (!(status & TREQ)) {
			
#ifdef DEBUG_MACIISI_ADB
			printk(KERN_DEBUG "extra data after packet: status %x ifr %x\n",
			       status, via[IFR]);
#endif
#if 0
			udelay(ADB_DELAY);
			via[B] |= TIP;

			maciisi_state = reading;
			reading_reply = 0;
			reply_ptr = maciisi_rbuf;
#else
			
			reading_reply = 0;
			goto switch_start;
#endif
			
			
		}
		else {
			
			i = maciisi_start();
			if(i == 0 && need_sync) {
				
				maciisi_sync(current_req);
			}
			if(i != -EBUSY)
				need_sync = 0;
		}
		break;

	default:
		printk("maciisi_interrupt: unknown maciisi_state %d?\n", maciisi_state);
	}
	local_irq_restore(flags);
	return IRQ_HANDLED;
}