📄 myudisk.c
字号:
if (cs->sc_data_direction == SCSI_DATA_WRITE) { doDefault = 1; } else switch (lengths[cs->cmnd[0]]) { case 'L': len = cs->cmnd[4]; break; case 'M': len = cs->cmnd[8]; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': len = lengths[cs->cmnd[0]]-'0'; break; case 'G': len = (((unsigned int)cs->cmnd[3])<<8) | cs->cmnd[4]; break; case 'H': len = (((unsigned int)cs->cmnd[7])<<8) | cs->cmnd[8]; break; case 'I': len = (((unsigned int)cs->cmnd[8])<<8) | cs->cmnd[9]; break; case 'R': len = (((unsigned int)cs->cmnd[2])<<16) | (((unsigned int)cs->cmnd[3])<<8) | cs->cmnd[4]; break; case 'S': len = (((unsigned int)cs->cmnd[3])<<16) | (((unsigned int)cs->cmnd[4])<<8) | cs->cmnd[5]; break; case 'T': len = (((unsigned int)cs->cmnd[6])<<16) | (((unsigned int)cs->cmnd[7])<<8) | cs->cmnd[8]; break; case 'U': len = (((unsigned int)cs->cmnd[7])<<16) | (((unsigned int)cs->cmnd[8])<<8) | cs->cmnd[9]; break; case 'C': len = (((unsigned int)cs->cmnd[2])<<24) | (((unsigned int)cs->cmnd[3])<<16) | (((unsigned int)cs->cmnd[4])<<8) | cs->cmnd[5]; break; case 'D': len = (((unsigned int)cs->cmnd[6])<<24) | (((unsigned int)cs->cmnd[7])<<16) | (((unsigned int)cs->cmnd[8])<<8) | cs->cmnd[9]; break; case 'V': len = 20; break; case 'W': len = 24; break; case 'B': /* Use buffer size due to different block sizes */ doDefault = 1; break; case 'X': dbg("Error: UNSUPPORTED COMMAND %02X\n", cs->cmnd[0]); doDefault = 1; break; case 'Z': /* Use buffer size due to mode dependence */ doDefault = 1; break; default: dbg("Error: COMMAND %02X out of range or table inconsistent (%c).\n", cs->cmnd[0], lengths[cs->cmnd[0]] ); doDefault = 1; } if ( doDefault == 1 ) { len = cs->data_payload_size; } dbg("doDefault %d, data length %u", doDefault, len); return len;}//////////////////////////////////////////////////////////////////////////////////////////////reset/* This issues a Bulk-only Reset to the device in question, including * clearing the subsequent endpoint halts that may occur. */int myudisk_Bulk_reset(struct usb_device *udev, struct usb_interface *interface, __u8 bulk_in_endpointAddr, __u8 bulk_out_endpointAddr){ int result; dbg("Bulk reset requested\n"); /* if the device was removed, then we're already reset */ if (!udev) return SUCCESS; result = usb_control_msg(udev, usb_sndctrlpipe(udev,0), MU_BULK_RESET_REQUEST, USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, interface->altsetting[0].bInterfaceNumber, NULL, 0, HZ*5); if (result < 0) { dbg("Bulk soft reset failed %d\n", result); return FAILED; } /* long wait for reset */ set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ*6); set_current_state(TASK_RUNNING); usb_clear_halt(udev, usb_rcvbulkpipe(udev, bulk_in_endpointAddr)); usb_clear_halt(udev, usb_sndbulkpipe(udev, bulk_out_endpointAddr)); dbg("Bulk soft reset completed\n"); return SUCCESS;}////////////////////////////////////////////////////////////////////////////////////////////////////int myudisk_Bulk_transport(struct usb_device *udev, struct usb_interface *interface, struct cmnd_struct *cs, unsigned char *bulk_buffer, int bulk_size, __u8 bulk_in_endpointAddr, __u8 bulk_out_endpointAddr){ struct bulk_cb_wrap *bcb; struct bulk_cs_wrap *bcs; int result; int pipe; int partial; char *buf; unsigned int transfer_amount; int ret = MYUDISK_TRANSPORT_ERROR; bcb = kmalloc(sizeof *bcb, in_interrupt() ? GFP_ATOMIC : GFP_NOIO); if (!bcb) { return MYUDISK_TRANSPORT_ERROR; } bcs = kmalloc(sizeof *bcs, in_interrupt() ? GFP_ATOMIC : GFP_NOIO); if (!bcs) { kfree(bcb); return MYUDISK_TRANSPORT_ERROR; } /* set up the command wrapper */ bcb->Signature = cpu_to_le32(MU_BULK_CB_SIGN); transfer_amount = myudisk_transfer_length(cs); bcb->DataTransferLength = cpu_to_le32(transfer_amount); bcb->Flags = cs->sc_data_direction == SCSI_DATA_READ ? 1 << 7 : 0; bcb->Tag = ++(cs->tag); bcb->Lun = cs->cmnd[1] >> 5; bcb->Length = cs->cmd_len; /* construct the pipe handle */ pipe = usb_sndbulkpipe(udev, bulk_out_endpointAddr); /* copy the command payload */ memset(bcb->CDB, 0, sizeof(bcb->CDB)); memcpy(bcb->CDB, cs->cmnd, bcb->Length); /* send it to out endpoint */ myudisk_debug_data ("command to send", MU_BULK_CB_WRAP_LEN, (unsigned char *)bcb); dbg("Bulk command S 0x%x T 0x%x Trg %d LUN %d L %d F %d CL %d", le32_to_cpu(bcb->Signature), bcb->Tag, (bcb->Lun >> 4), (bcb->Lun & 0x0F), bcb->DataTransferLength, bcb->Flags, bcb->Length); result = usb_bulk_msg(udev, pipe, bcb, MU_BULK_CB_WRAP_LEN, &partial, MYUDISK_TIMEOUT); dbg("Bulk command transfer result=%d, xferred %d/%d", result, partial, MU_BULK_CB_WRAP_LEN); /* if the command was aborted, indicate that */ if (result == -ECONNRESET) { ret = MYUDISK_TRANSPORT_ABORTED; goto out; } /* if we stall, we need to clear it before we go on */ if (result == -EPIPE) { dbg("clearing endpoint halt for pipe 0x%x", pipe); result = usb_clear_halt(udev, pipe); /* if the command was aborted, indicate that */ if (result == -ECONNRESET) { ret = MYUDISK_TRANSPORT_ABORTED; goto out; } result = -EPIPE; } else if (result) { /* unknown error -- we've got a problem */ ret = MYUDISK_TRANSPORT_ERROR; goto out; } dbg("----cmnd end\n"); /* if the command transfered well, then we go to the data stage */ if (result == 0) { /* send/receive data payload, if there is any */ if (bcb->DataTransferLength) { /* calculate the appropriate pipe and buffer information */ if (cs->sc_data_direction == SCSI_DATA_READ) { pipe = usb_rcvbulkpipe(udev, bulk_in_endpointAddr); buf = bulk_buffer; if (transfer_amount > bulk_size) { dbg("illegal DataTransferLength!"); transfer_amount = bulk_size; } } else { pipe = usb_sndbulkpipe(udev, bulk_out_endpointAddr); buf = bulk_buffer; if (transfer_amount > bulk_size) { dbg("illegal DataTransferLength!"); transfer_amount = bulk_size; } } /* transfer the data */ dbg("xfer %d bytes data", transfer_amount); result = usb_bulk_msg(udev, pipe, buf, transfer_amount, &partial, MYUDISK_TIMEOUT); cs->data_payload_actualSize = partial; dbg("Bulk data transfer result: %d, xferred %d/%d", result, partial, transfer_amount);// myudisk_debug_data ("data transfered", partial, buf); /* if we stall, we need to clear it before we go on */ if (result == -EPIPE) { dbg("clearing endpoint halt for pipe 0x%x", pipe); usb_clear_halt(udev, pipe); } /* if it was aborted, we need to indicate that */ if (result) { ret = MYUDISK_TRANSPORT_ABORTED; goto out; } } } dbg("----data end\n"); /* See flow chart on pg 15 of the Bulk Only Transport spec for * an explanation of how this code works. */ /* construct the pipe handle */ pipe = usb_rcvbulkpipe(udev, bulk_in_endpointAddr); /* get CSW for device status */ dbg("Attempting to get CSW..."); result = usb_bulk_msg(udev, pipe, bcs, MU_BULK_CS_WRAP_LEN, &partial, MYUDISK_TIMEOUT); dbg("Bulk status transfer result = %d, xferred %d/%d", result, partial, MU_BULK_CS_WRAP_LEN); /* if the command was aborted, indicate that */ if (result == -ECONNRESET) { ret = MYUDISK_TRANSPORT_ABORTED; goto out; } /* did the attempt to read the CSW fail? */ if (result == -EPIPE) { dbg("clearing endpoint halt for pipe 0x%x", pipe); result = usb_clear_halt(udev, pipe); /* if the command was aborted, indicate that */ if (result == -ECONNRESET) { ret = MYUDISK_TRANSPORT_ABORTED; goto out; } /* get the status again */ dbg("Attempting to get CSW (2nd try)..."); result = usb_bulk_msg(udev, pipe, bcs, MU_BULK_CS_WRAP_LEN, &partial, MYUDISK_TIMEOUT); /* if the command was aborted, indicate that */ if (result == -ECONNRESET) { ret = MYUDISK_TRANSPORT_ABORTED; goto out; } /* if it fails again, we need a reset and return an error*/ if (result == -EPIPE) { dbg("clearing halt for pipe 0x%x", pipe); result = usb_clear_halt(udev, pipe); /* if the command was aborted, indicate that */ if (result == -ECONNRESET) { ret = MYUDISK_TRANSPORT_ABORTED; } else { ret = MYUDISK_TRANSPORT_ERROR; } goto out; } } /* if we still have a failure at this point, we're in trouble */ if (result) { ret = MYUDISK_TRANSPORT_ERROR; goto out; } /* check bulk status */ myudisk_debug_data ("status data recerived", partial, (unsigned char *)bcs); dbg("Bulk status Sig 0x%x T 0x%x R %d Stat 0x%x", le32_to_cpu(bcs->Signature), bcs->Tag, bcs->Residue, bcs->Status); if ((bcs->Signature != cpu_to_le32(MU_BULK_CS_SIGN) && bcs->Signature != cpu_to_le32(MU_BULK_CS_OLYMPUS_SIGN)) || bcs->Tag != bcb->Tag || bcs->Status > MU_BULK_STAT_PHASE || partial != 13) { dbg("Bulk logical error"); ret = MYUDISK_TRANSPORT_ERROR; goto out; } /* based on the status code, we report good or bad */ switch (bcs->Status) { case MU_BULK_STAT_OK: /* command good -- note that data could be short */ ret = MYUDISK_TRANSPORT_GOOD; goto out; case MU_BULK_STAT_FAIL: /* command failed */ ret = MYUDISK_TRANSPORT_FAILED; goto out; case MU_BULK_STAT_PHASE: /* phase error -- note that a transport reset will be * invoked by the invoke_transport() function */ ret = MYUDISK_TRANSPORT_ERROR; goto out; } /* we should never get here, but if we do, we're in trouble */ dbg("we should never get here."); out: if (ret == MYUDISK_TRANSPORT_GOOD) { dbg("transport indicates command was successful\n"); } else if (ret == MYUDISK_TRANSPORT_ABORTED || ret == MYUDISK_TRANSPORT_ERROR) { myudisk_Bulk_reset(udev, interface, bulk_in_endpointAddr, bulk_out_endpointAddr); dbg("transport indicates command was aborted\n"); } kfree(bcb); kfree(bcs); return ret;}//////////////////////////////////////////////////////////////////////////////////////////////static void myudisk_disconnect(struct usb_device *udev, void *ptr){ struct my_udisk *dev; int minor; dev = (struct my_udisk *)ptr; down (&minor_table_mutex); down (&dev->sem); minor = dev->minor; /* remove our devfs node */ devfs_unregister(dev->devfs); /* if the device is not opened, then we clean up right now */ if (!dev->open_count) { up (&dev->sem); myudisk_delete (dev); } else { dev->udev = NULL; up (&dev->sem); } info("My UDisk #%d now disconnected", minor); up (&minor_table_mutex);}/** * my_udisk_init */static int __init my_udisk_init(void){ int result; /* register this driver with the USB subsystem */ result = usb_register(&myudisk_driver); if (result < 0) { err("usb_register failed for the "__FILE__" driver. Error number %d", result); return -1; } info(DRIVER_DESC " " DRIVER_VERSION); /* 块大小必须是扇区大小的整数倍 */ /*if (myudisk_blocksize & ((1 << MYUDISK_SECTOR_BITS)-1)) { dbg("Block size not a multiple of sector size\n"); return -EINVAL; }*/ /* 分配存储空间 */ /*myudisk_storage = (char *) vmalloc(1024*myudisk_size); if (myudisk_storage == NULL) { dbg("Not enough memory. Try a smaller size.\n"); return -ENOMEM; }*/ //memset(myudisk_storage, 0, 1024*myudisk_size); /* 【重要】向系统注册块设备 */ result = register_blkdev(MAJOR_NR, DEVICE_NAME, &myudisk_fops); if (result) { dbg("couldn't register block device\n"); return result; } /* 在系统中注册块的大小、存储容量等参数 */ hardsect_size[MAJOR_NR] = &myudisk_hard; blksize_size[MAJOR_NR] = &myudisk_soft; blk_size[MAJOR_NR] = &myudisk_size; /* 在系统中注册响应读写请求的函数 */ blk_queue_make_request(BLK_DEFAULT_QUEUE(MAJOR_NR), &myudisk_request); read_ahead[MAJOR_NR] = myudisk_readahead; return 0;}/** * my_udisk_exit */static void __exit my_udisk_exit(void){ /* deregister this driver with the USB subsystem */ usb_deregister(&myudisk_driver); unregister_blkdev(MAJOR_NR, DEVICE_NAME); invalidate_buffers(MKDEV(MAJOR_NR,0)); /* remove our request function */ blk_dev[MAJOR_NR].request_queue.request_fn = 0; }module_init (my_udisk_init);module_exit (my_udisk_exit);MODULE_AUTHOR(DRIVER_AUTHOR);MODULE_DESCRIPTION(DRIVER_DESC);MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -