de1_dev.c
来自「linux嵌入式课程实践中的一个关于声卡驱动程序 。」· C语言 代码 · 共 1,083 行 · 第 1/2 页
C
1,083 行
{ int port = 0; unsigned int bmRequestType; unsigned int bRequest; int return_status = ERROR; struct de1_priv * priv = (recv_urb->device->function_instance_array+port)->privdata; cy_dbg("de1_recv_setup enter"); bmRequestType = recv_urb->device_request.bmRequestType & USB_REQ_TYPE_MASK; bRequest = recv_urb->device_request.bRequest; if((recv_urb != NULL) && (recv_urb->status != RECV_ERROR)) { if(recv_urb->actual_length <= 0) { usbd_recycle_urb(recv_urb); } // CHECK FOR VENDOR SPECIFIC SETUP COMMAND if(bmRequestType & USB_REQ_TYPE_VENDOR) { switch(bRequest) { case 0: /* status report from the host, place the data on the * vendor queue */ urb_append_irq(&priv->vendor_rcv, recv_urb); return_status = SUCCESS; break; case 1: /* update seven segment display to sync with host */ urb_append_irq(&priv->vendor_rcv, recv_urb); return_status = SUCCESS; break; default: cy_info("DE1_RECV_SETUP: Invalid vendor type."); break; } } } return(return_status); }#endif/****************************************************************************** * PARAMETERS: * * DESCRIPTION: * * RETURNS: * */static ssize_t de1_read(struct file *file, char *buffer, size_t count, loff_t *ppos){ ssize_t ret; struct de1_priv * priv = (struct de1_priv *) file->private_data; down(&priv->sem); ret = ep_read( priv, buffer, count, BULK_OUT_EP ); up(&priv->sem); return ret;}/****************************************************************************** * PARAMETERS: * * DESCRIPTION: * * RETURNS: * */static ssize_t ep_read(struct de1_priv *priv, char *buffer, size_t count, int endpoint){ struct usbd_urb * urb; ssize_t return_value = ERROR; int length; struct urb_link *urb_link; cy_dbg("ep_read enter, count:%d, ep:%d", count, endpoint); if( endpoint == INT_OUT_EP ) { urb_link = &priv->int_out_rcv; } else if( endpoint == BULK_OUT_EP ) { urb_link = &priv->bulk_out_rcv; } else { cy_err("Reading on unknown endpoint"); return -EINVAL; } /* verify that the device wasn't unplugged */ if( priv->device != NULL && !( priv->device->status == USBD_OK && priv->device->device_state == DEVICE_CONFIGURED ) ) { cy_dbg("device not connected"); return -ENOTCONN; } if( (urb = first_urb_detached(urb_link)) == NULL ) { return -EAGAIN; } length = urb->actual_length; if(count >= length) { if( copy_to_user(buffer, urb->buffer, length) ) { /* put back on queue */ urb_link_init(&urb->link); urb_append_irq(urb_link, urb); cy_err("copy_to_user failure"); return_value = -EFAULT; } else { usbd_recycle_urb(urb); return_value = length; } cy_dbg("1:de1_read, return:%d", return_value); } else { /* there is more data in this URB than is currently requested, return the requested amount, and then place the remaining data back in the receive queue, at the head. */ int difference; difference = length - count; /* size of remaining data of URB buffer */ if( copy_to_user(buffer, urb->buffer, count) ) { /* put back on queue */ urb_link_init(&urb->link); urb_append_irq(urb_link, urb); cy_err("copy_to_user failure"); return_value = -EFAULT; } else { memcpy(urb->buffer, urb->buffer + count, difference); urb->actual_length = difference; /* put back on queue */ urb_link_init(&urb->link); urb_append_irq(urb_link, urb); return_value = count; } cy_dbg("2:de1_read, return:%d", return_value); } return return_value;}/****************************************************************************** * PARAMETERS: * * DESCRIPTION: * * RETURNS: * */static ssize_t de1_write(struct file *file, const char *buffer, size_t count, loff_t *ppos){ ssize_t ret; struct de1_priv *priv = (struct de1_priv *) file->private_data; down(&priv->sem); ret = ep_write(priv, buffer, count, BULK_IN_EP); up(&priv->sem); return ret;}/****************************************************************************** * PARAMETERS: * * DESCRIPTION: * * RETURNS: * */static ssize_t ep_write(struct de1_priv *priv, const char *buffer, size_t count, int endpoint){ struct usbd_urb * urb; ssize_t return_value = ERROR; ssize_t bytes_written = 0; struct urb_link *urb_link; cy_dbg("ep_write enter - count:%d, ep:%d", count, endpoint); /* verify that the device wasn't unplugged */ if( priv->device != NULL && !( priv->device->status == USBD_OK && priv->device->device_state == DEVICE_CONFIGURED ) ) { cy_dbg("device not connected"); return -ENOTCONN; } /* is the count set */ if(count <= 0 || buffer == NULL) { cy_err("invalid count/buffer"); return -EINVAL; } if( endpoint == INT_IN_EP ) { urb_link = &priv->int_in_tx; } else if( endpoint == BULK_IN_EP ) { urb_link = &priv->bulk_in_tx; } else { cy_err("Writing on unknown endpoint"); return -EINVAL; } /* we have some data to send, get a URB and send it */ //urb = usbd_alloc_urb(priv->device, priv->device->function_instance_array, //BULK_IN_EP, count); urb = first_urb_detached(urb_link); if( urb == 0 ) { cy_dbg("no urb pointer"); return -EAGAIN; }#if 0 { unsigned long int_flags; local_irq_save(int_flags); --free_urb; local_irq_restore(int_flags); }#endif /* we can only write as much as 1 urb will hold */ bytes_written = (count > urb->buffer_length) ? urb->buffer_length : count; //bytes_written = count; /* copy the data from userspace into our urb */ if (copy_from_user(urb->buffer, buffer, bytes_written)) { de1_recycle_urb(urb, urb_link); cy_err("copy from user error"); return -EFAULT; } urb->actual_length = bytes_written; /* submit the URB */ //HWTrace(0x7171); if( usbd_send_urb(urb) == 0 ) { return_value = bytes_written; } else { cy_err("Failed to send urb"); de1_recycle_urb(urb, urb_link); return_value = -EAGAIN; } cy_dbg("write exit"); return return_value;}/****************************************************************************** * PARAMETERS: * * DESCRIPTION: * * RETURNS: * */static int de1_open(struct inode *inode, struct file *file){ int subminor; int retval = 0; cy_dbg("de1_open enter"); subminor = MINOR(inode->i_rdev) - USB_DE1_MINOR_BASE; if ((subminor < 0) || (subminor >= MAX_DEVICES)) { return -ENODEV; } MOD_INC_USE_COUNT; /* lock this device */ down(&de1_priv->sem); /* increment our usage count for the driver */ ++de1_priv->open_count; /* save our object in the file's private structure */ file->private_data = de1_priv; /* unlock this device */ up(&de1_priv->sem); cy_dbg("de1_open exit"); return retval;}/****************************************************************************** * PARAMETERS: * * DESCRIPTION: * * RETURNS: * */int de1_release(struct inode *inode, struct file *filp){ cy_dbg("de1_release enter"); if (de1_priv == NULL) { cy_err("%s - object is NULL", __FUNCTION__); return -EFAULT; } /* lock our device */ down(&de1_priv->sem); /* decrement our usage count for the module */ MOD_DEC_USE_COUNT; up(&de1_priv->sem); cy_dbg("de1_release exit"); return 0;}/****************************************************************************** * PARAMETERS: * * DESCRIPTION: * * RETURNS: * */static int de1_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ struct de1_priv * priv; int return_value = ERROR; cy_dbg("de1_ioctl enter, %d", cmd); if((priv = (struct de1_priv *) file->private_data) != NULL) { /* lock this object */ down(&priv->sem); /* verify that the device wasn't unplugged */ if(priv->device != NULL) { /* we have a valid device */ switch(cmd) { case IOCTL_ACCEPT_HNP: usbd_device_event(de1_priv->device, DEVICE_ACCEPT_HNP, 0); return_value = SUCCESS; break; case IOCTL_REQUEST_SRP: usbd_device_event(de1_priv->device, DEVICE_REQUEST_SRP, 0); return_value = SUCCESS; break; case IOCTL_GET_DE_RPT: { unsigned char count; if( arg != 0 && !copy_from_user(&count, (void*)arg, 1) ) { return_value = ep_read( priv, (char*)arg, count, INT_OUT_EP ); if( return_value >=0 ) { return_value = SUCCESS; } } } break; case IOCTL_SEND_DE_RPT: { unsigned char count; if( arg != 0 && !copy_from_user(&count, (void*)arg, 1) ) { cy_dbg("rpt size: %d", count); return_value = ep_write( priv, (char*)arg, count, INT_IN_EP ); if( return_value >=0 ) { return_value = SUCCESS; } } } break; case TCGETS: break; default: cy_err("unrecognized ioctl command: 0x%x", cmd); break; } } /* unlock the device */ up(&priv->sem); } cy_dbg("de1_ioctl exit"); return return_value;}/****************************************************************************** * PARAMETERS: * * DESCRIPTION: recycle transmit urbs * * RETURNS: * */void de1_recycle_urb(struct usbd_urb *urb, struct urb_link *link){ if( urb != 0 && link != 0) { unsigned long int_flags; //HWTrace(0x7474); urb_link_init(&urb->link); local_irq_save(int_flags); urb_append_irq(link, urb); //++free_urb; local_irq_restore(int_flags); }}/****************************************************************************** * PARAMETERS: * * DESCRIPTION: * * RETURNS: * */int __init de1_modinit(void){ int err; cy_dbg("de1_modinit enter"); /* optional name override */ de1_function_driver.name = DRIVER_NAME; /* register this function driver with the USBD core */ err = usbd_register_function(&de1_function_driver); if( err != 0 ) { cy_err("usbd_register_function() failed."); } return err;}/****************************************************************************** * PARAMETERS: * * DESCRIPTION: * * RETURNS: * */void __exit de1_modexit(void){ cy_dbg("de1_modexit enter"); usbd_deregister_function(&de1_function_driver);}/*****************************************************************************/#ifdef MODULEmodule_init(de1_modinit);module_exit(de1_modexit);#endif
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?