본문 바로가기

Linux

[USB] module registrations

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
//
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);
}

//
// USB release
//
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 handler
//
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 handler
//
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;    }

'Linux' 카테고리의 다른 글

.bash_profile 에서의 패스(Path) 설정  (0) 2013.09.26
마운트시 한글 지원 (NTFS | MOUNT | HANGLE)  (0) 2013.09.26
[USB] Device Descriptor  (0) 2013.09.26
How to get USB devices working under Linux  (0) 2013.09.26
[Kernel] USB support  (0) 2013.09.26