Beispiel #1
0
/* Send a request, possibly waiting for a reply */
static int
maciisi_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;
}
static int
maciisi_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)
	{
		if(i == -EBUSY && sync)
			need_sync = 1;
		else
			need_sync = 0;
		return i;
	}
	if(sync)
		maciisi_sync(req);
	
	return 0;
}
Beispiel #3
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;
}
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;
}