Linux

USB

aucd29 2013. 9. 26. 20:53
//
// Module Registration
//
int init_module(void)
{
        int result;

        result = register_chrdev(usb_major, "USB", &usb_fops);
        if (result < 0) {
            printk("USB can't get major \n");
            return result;
        }
        else if (usb_major == 0) usb_major = result;
        printk("USB Init, major number : %d\n", result);
        return 0;
}

void cleanup_module(void)
{
    unregister_chrdev(usb_major, "USB");
}

//
// usb_open();, usb_release();
//
static int usb_open(struct inode * inode, struct file * file)
{
    if (usb_usage!=0)
            return -EBUSY;
    usbctl_create_descriptors();            
    usb_init();
    MOD_INC_USE_COUNT;
    usb_usage=1;
    Ser0UDCCR = 0;
    printk("USB opened\n");
    return(0);
}

static int usb_release(struct inode * inode, struct file * file)
{    
    MOD_DEC_USE_COUNT;
    usb_usage=0;
    usb_disable();
    free_irq(IRQ_Ser0UDC, NULL);
    return 0;
}

//
// usb_init();
//
int usb_init(void)
{
    int ret;
    
    usb_disable_interrupts(0);
    usb_disable();
    
    ret = request_irq(IRQ_Ser0UDC, usb_int_hndlr, SA_INTERRUPT,
             "USB", NULL);
    if (ret) {
        printk("usb: Couldn't request USB irq\n");
        return ret;
    }
    usb_enable();
    usb_enable_interrupts(0);
    return 0;
}

//
// usb_int_hndlr();
//
static void usb_int_hndlr(int irq, void *dev_id, struct pt_regs *regs)
{
    int status;

    status = Ser0UDCSR;
    UDC_flip (Ser0UDCSR, status);    
        
    if (status & UDCSR_EIR) ep0_int_hndlr(status);
    if (status & UDCSR_RIR) ep1_int_hndlr(status);
    if (status & UDCSR_TIR) ep2_int_hndlr(status);]

    if (status & UDCSR_RSTIR) {

        printk("usb_ctl: resetting\n");
        reset();    
    }
    else {
        printk("clearing\n");    
        UDC_set(Ser0UDCCR, UDCCR_REM);
    }    
}

//
// ep0_int_hndlr();
//
switch (ep0_state)
{
    case EP0_IDLE :
        ep0_idle(ep0_status);        // Control Data Receive &
        break;            //         Parsing Command
    case EP0_IN_DATA_PHASE :
        ep0_in_data(ep0_status);
        break;
    case EP0_END_XFER :
        ep0_end_xfer(ep0_status);
        break;
    default :
        break;
}

//
// ep0_idle();
//
void ep0_idle(unsigned int ep0_status)
{
     if (ep0_status & UDCCS0_OPR)
     {
         ep0_read_data(&request);
         if ((request.bmRequestType & 0x60) == 0)
         {
             switch (request.bRequest)
             {
                 case SET_ADDRESS : ep0_set_address(&request);
                 case GET_DESCRIPTOR : ep0_get_desc(&request, ep0_status);
                 case SET_CONFIGURATION :
                  ep0_set_configuration(&request, ep0_status);
                     ……….
             }
        }
        else
        {
            switch(request.bRequest & 0x0f)
            {
             case 3 :
                 ep0_state = EP0_IN_DATA_PHASE;
                 buffer = buf_temp; buffer_cnt = request.wLength;
                 ep0_in_data(ep0_status);
     case 4 :
                 ep0_serviced_opr_data_end();
                 break;
            }
        }
}

//
// ep0_read_data();
//
int ep0_read_data(usb_dev_request_t *request)
{
    ep0_write_count = *(UDCWC);
    while (ep0_write_count>0) {
     do {
             data = *(UDCD0);
    udelay(1);
    count = *(UDCWC);
        } while (count == ep0_write_count);
        ep0_write_count = count;
        pkt[i] = (char) (data & 0xff); i++;
        if (i>=8 && ep0_write_count > 0)    {
            printk("EP0 : reading too much data\n");    break;
        }
    }
    memcpy(request, pkt, sizeof(usb_dev_request_t));
}

//
// ep0_in_data();
//
void ep0_in_data(unsigned int ep0_status)
{
    if (!(ep0_status & 0x24)) { // if stalled and IPR set???    
        if (buffer_cnt > 8)    {
        transfer_cnt = 8; buffer_cnt = buffer_cnt - 8;
        } else transfer_cnt = buffer_cnt;    buffer_cnt = 0;
        
        ep0_write_count_s=0; writes=0;
        do {
                 *(UDCD0) = (unsigned long) buffer[ep0_write_count_s];
     ep0_write_count_s = *(UDCWC); writes++;
        } while ((ep0_write_count_s < transfer_cnt) && (writes<1000));
        buffer += transfer_cnt;

        if (buffer_cnt == 0) {
            ep0_state = EP0_END_XFER;
    if (end_xfer != END_XFER_FORCED) {
                     *(UDCCS0) = UDCCS0_DE;
         }
    }

    *(UDCCS0) = UDCCS0_IPR;
}