/* Start running. Must have called usb_open (above) first */ int sa1100_usb_start( void ) { usbd_info.state = USB_STATE_SUSPENDED; /* Enable UDC and mask everything */ UDC_write(Ser0UDCCR , 0xFC); /* clear stall - receiver seems to start stalled? 19Jan01ww */ /* also clear other stuff just to be thurough 22Feb01ww */ UDC_clear(Ser0UDCCS1, UDCCS1_FST | UDCCS1_RPE | UDCCS1_RPC ); UDC_clear(Ser0UDCCS2, UDCCS2_FST | UDCCS2_TPE | UDCCS2_TPC ); rx_pktsize = 8; // OJO tx_pktsize = 1; // OJO /* flush DMA and fire through some -EAGAINs */ ep1_init( usbd_info.dmach_rx ); ep2_init( usbd_info.dmach_tx ); /* clear all top-level sources */ Ser0UDCSR = UDCSR_RSTIR | UDCSR_RESIR | UDCSR_EIR | UDCSR_RIR | UDCSR_TIR | UDCSR_SUSIR ; /* EXERIMENT - a short line in the spec says toggling this ..bit diddles the internal state machine in the udc to ..expect a suspend */ Ser0UDCCR |= UDCCR_RESIM; /* END EXPERIMENT 10Feb01ww */ UDC_write( Ser0UDCCR, UDCCR_SUSIM | UDCCR_TIM); /* clear all top-level sources */ Ser0UDCSR = UDCSR_RSTIR | UDCSR_RESIR | UDCSR_EIR | UDCSR_RIR | UDCSR_TIR | UDCSR_SUSIR ; return 0; }
/* * This gets called when we receive a SET_CONFIGURATION packet to EP0. * We were configured. We can now send packets to the host. */ void udc_ep2_config(struct sausb_dev *usb, unsigned int maxpktsize) { /* * We shouldn't be transmitting anything... */ BUG_ON(usb->ep[1].buflen); BUG_ON(usb->ep[1].pktlen); /* * Set our configuration. */ usb->ep[1].maxpktsize = maxpktsize; usb->ep[1].configured = 1; /* * Clear any pending TPC status. */ udc_set_cs2(UDCCS2_TPC, UDCCS2_TPC, 0); /* * Enable EP2 interrupts. */ usb->udccr &= ~UDCCR_TIM; UDC_write(Ser0UDCCR, usb->udccr); usb->ep[1].udccs = 0; }
static void ep1_start(void) { PRINTKD( "[%lu]ep1_start dma_len %d remain %d pkt %d\n", (jiffies-start_time)*10, ep1_curdmalen, ep1_remain, rx_pktsize); sa1100_clear_dma(dmachn_rx); if (!ep1_curdmalen) { // ep1_curdmalen is min (rx_pktsize , ep1_remain) ep1_curdmalen = rx_pktsize; if (ep1_curdmalen > ep1_remain) ep1_curdmalen = ep1_remain; ep1_curdmapos = pci_map_single(NULL, ep1_curdmabuf, ep1_curdmalen, PCI_DMA_FROMDEVICE); } UDC_write( Ser0UDCOMP, ep1_curdmalen - 1); sa1100_start_dma(dmachn_rx, ep1_curdmapos, ep1_curdmalen); if ( naking ) { /* turn off NAK of OUT packets, if set */ UDC_flip( Ser0UDCCS1, UDCCS1_RPC ); naking = 0; } }
int ep1_init(dma_regs_t *chn) { UDC_write( Ser0UDCOMP, rx_pktsize-1 ); dmachn_rx = chn; sa1100_clear_dma(dmachn_rx); ep1_done(-EAGAIN); return 0; }
/* set feature stall executing, async */ static void ep2_start(struct sausb_dev *usb) { ep2_curdmalen = min(ep2_remain, usb->ep[1].maxpktsize); if (ep2_curdmalen == 0) return; /* * must do this _before_ queue buffer.. * stop NAKing IN tokens */ udc_set_cs2(usb->ep[1].udccs | UDCCS2_TPC, UDCCS2_TPC, 0); UDC_write(Ser0UDCIMP, ep2_curdmalen - 1); /* Remove if never seen...8Mar01ww */ { int massive_attack = 20; while (Ser0UDCIMP != ep2_curdmalen - 1 && massive_attack--) { printk("usbsnd: Oh no you don't! Let me spin..."); udelay(500); printk("and try again...\n"); UDC_write(Ser0UDCIMP, ep2_curdmalen - 1); } if (massive_attack != 20) { if (Ser0UDCIMP != ep2_curdmalen - 1) printk("usbsnd: Massive attack FAILED. %d\n", 20 - massive_attack); else printk("usbsnd: Massive attack WORKED. %d\n", 20 - massive_attack); } } /* End remove if never seen... 8Mar01ww */ /* * fight stupid silicon bug */ Ser0UDCAR = usb->ctl->address; sa1100_start_dma(usb->ep[1].dmach, usb->ep[1].pktdma, ep2_curdmalen); }
/* * We saw a reset from the attached hub, or were deconfigured. * This means we are no longer configured. */ void udc_ep2_reset(struct sausb_dev *usb) { /* * Disable EP2 interrupts. */ usb->udccr |= UDCCR_TIM; UDC_write(Ser0UDCCR, usb->udccr); usb->ep[1].configured = 0; usb->ep[1].maxpktsize = 0; sa1100_reset_dma(usb->ep[1].dmach); udc_ep2_done(usb, -EINTR); }
static void hub_interrupt_complete(int flag, int size) { int flags; PRINTKI( "[%lu]Hub_interrupt_complete (status %d)\n",(jiffies-start_time)*10, flag); local_irq_save(flags); if (flag == 0) { //printk( "hub_interrupt_complete: ¿queda pendiente?\n"); hub_interrupt_queued = 0; } else { printk( "hub_interrupt_complete con error?: flag %d, size %d\n", flag, size); } local_irq_restore(flags); // Mask EP2 interrupts Ser0UDCCR = 0xFC; UDC_write(Ser0UDCCR, UDCCR_TIM); //UDC_write(Ser0UDCCR, UDCCR_TIM | UDCCR_REM); // Errata 29 if (device_retry>0) { PRINTKI( "[%lu]GetHub/PortStatus: retry port %d \n", (jiffies-start_time)*10, device_retry); } // Keep sending Device 5 connected until PORT_RESET received if (machine_state==DEVICE5_WAIT_READY && device_retry>0) { machine_state=DEVICE4_READY; SET_TIMER (10); } // Keep sending Device 3 disconnected until PORT_STATUS received if (machine_state==DEVICE3_WAIT_DISCONNECT && device_retry>0) { machine_state=DEVICE5_READY; SET_TIMER (10); } }
static void udc_int_hndlr(int irq, void *dev_id, struct pt_regs *regs) { __u32 status = Ser0UDCSR; if (start_time==0) { start_time = jiffies; } //PRINTKD("[%lu]Status %d Mask %d\n", (jiffies-start_time)*10, status, Ser0UDCCR); UDC_flip(Ser0UDCSR, status); // clear all pending sources /* ReSeT Interrupt Request - UDC has been reset */ if (status & UDCSR_RSTIR) { Ser0UDCCR = 0xFC; if (second_reset) { UDC_write(Ser0UDCCR, UDCCR_TIM); //UDC_write(Ser0UDCCR, UDCCR_TIM | UDCCR_REM); // Errata 29 } else { Ser0UDCCR = UDCCR_TIM; //Ser0UDCCR = UDCCR_TIM | UDCCR_REM; // Errata 29 } if (Ser0UDCCR & UDCCR_TIM || second_reset==1) { /* starting 20ms or so reset sequence now... */ ep0_reset(); // just set state to idle ep1_reset(); // flush dma, clear false stall ep2_reset(); // flush dma, clear false stall } second_reset = 1; //UDC_flip(Ser0UDCSR, status); // clear all pending sources PRINTKI("[%lu]Reset: Mask %d\n", (jiffies-start_time)*10, Ser0UDCCR); return; } second_reset = 0; // /* RESume Interrupt Request ojo eliminar?*/ if ( status & UDCSR_RESIR ) { core_kicker(); Ser0UDCCR = 0xFC; Ser0UDCCR = UDCCR_TIM | UDCCR_RESIM; //UDC_flip(Ser0UDCSR, status); // clear all pending sources PRINTKD("[%lu]Resume: Mask %d\n", (jiffies-start_time)*10, Ser0UDCCR); return; } /* SUSpend Interrupt Request */ if ( status & UDCSR_SUSIR ) { Ser0UDCCR = 0xFC; // Does not seems to help either to be necessary // if (tr==2) { // core_kicker(); // } UDC_write(Ser0UDCCR, UDCCR_TIM | UDCCR_SUSIM); //UDC_write(Ser0UDCCR, UDCCR_TIM | UDCCR_SUSIM | UDCCR_REM); // Errata 29 //UDC_flip(Ser0UDCSR, status); // clear all pending sources PRINTKI("[%lu]Suspended: Mask %d\n", (jiffies-start_time)*10, Ser0UDCCR); return; } //UDC_flip(Ser0UDCSR, status); // clear all pending sources if (status & UDCSR_RIR) ep1_int_hndlr(); if (status & UDCSR_TIR) ep2_int_hndlr(); if (status & UDCSR_EIR) ep0_int_hndlr(); }