📄 microtek.c
字号:
return;}static void mts_get_status( struct urb *transfer )/* Interrupt context! */{ MTS_INT_INIT(); mts_int_submit_urb(transfer, usb_rcvbulkpipe(context->instance->usb_dev, context->instance->ep_response), &context->status, 1, mts_transfer_done );}static void mts_data_done( struct urb* transfer )/* Interrupt context! */{ MTS_INT_INIT(); if ( context->data_length != transfer->actual_length ) { context->srb->resid = context->data_length - transfer->actual_length; } else if ( transfer->status ) { context->srb->result = (transfer->status == -ENOENT ? DID_ABORT : DID_ERROR)<<16; } mts_get_status(transfer); return;}static void mts_command_done( struct urb *transfer )/* Interrupt context! */{ MTS_INT_INIT(); if ( transfer->status ) { if (transfer->status == -ENOENT) { /* We are being killed */ MTS_DEBUG_GOT_HERE(); context->srb->result = DID_ABORT<<16; } else { /* A genuine error has occured */ MTS_DEBUG_GOT_HERE(); context->srb->result = DID_ERROR<<16; } mts_transfer_cleanup(transfer); return; } if ( context->data ) { mts_int_submit_urb(transfer, context->data_pipe, context->data, context->data_length, context->srb->use_sg ? mts_do_sg : mts_data_done); } else mts_get_status(transfer); return;}static void mts_do_sg (struct urb* transfer){ struct scatterlist * sg; MTS_INT_INIT(); MTS_DEBUG("Processing fragment %d of %d\n", context->fragment,context->srb->use_sg); if (transfer->status) { context->srb->result = (transfer->status == -ENOENT ? DID_ABORT : DID_ERROR)<<16; mts_transfer_cleanup(transfer); } sg = context->srb->buffer; context->fragment++; mts_int_submit_urb(transfer, context->data_pipe, sg[context->fragment].address, sg[context->fragment].length, context->fragment + 1 == context->srb->use_sg ? mts_data_done : mts_do_sg); return;}static const u8 mts_read_image_sig[] = { 0x28, 00, 00, 00 };static const u8 mts_read_image_sig_len = 4;static const unsigned char mts_direction[256/8] = { 0x28, 0x81, 0x14, 0x14, 0x20, 0x01, 0x90, 0x77, 0x0C, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};#define MTS_DIRECTION_IS_IN(x) ((mts_direction[x>>3] >> (x & 7)) & 1)static voidmts_build_transfer_context( Scsi_Cmnd *srb, struct mts_desc* desc ){ int pipe; struct scatterlist * sg; MTS_DEBUG_GOT_HERE(); desc->context.instance = desc; desc->context.srb = srb; desc->context.fragment = 0; if (!srb->use_sg) { if ( !srb->bufflen ){ desc->context.data = 0; desc->context.data_length = 0; return; } else { desc->context.data = srb->buffer; desc->context.data_length = srb->bufflen; MTS_DEBUG("length = %d or %d\n", srb->request_bufflen, srb->bufflen); } } else { MTS_DEBUG("Using scatter/gather\n"); sg = srb->buffer; desc->context.data = sg[0].address; desc->context.data_length = sg[0].length; } /* can't rely on srb->sc_data_direction */ /* Brutally ripped from usb-storage */ if ( !memcmp( srb->cmnd, mts_read_image_sig, mts_read_image_sig_len )) { pipe = usb_rcvbulkpipe(desc->usb_dev,desc->ep_image); MTS_DEBUG( "transfering from desc->ep_image == %d\n", (int)desc->ep_image ); } else if ( MTS_DIRECTION_IS_IN(srb->cmnd[0]) ) { pipe = usb_rcvbulkpipe(desc->usb_dev,desc->ep_response); MTS_DEBUG( "transfering from desc->ep_response == %d\n", (int)desc->ep_response); } else { MTS_DEBUG("transfering to desc->ep_out == %d\n", (int)desc->ep_out); pipe = usb_sndbulkpipe(desc->usb_dev,desc->ep_out); } desc->context.data_pipe = pipe;}staticint mts_scsi_queuecommand( Scsi_Cmnd *srb, mts_scsi_cmnd_callback callback ){ struct mts_desc* desc = (struct mts_desc*)(srb->host->hostdata[0]); int err = 0; int res; MTS_DEBUG_GOT_HERE(); mts_show_command(srb); mts_debug_dump(desc); if ( srb->device->lun || srb->device->id || srb->device->channel ) { MTS_DEBUG("Command to LUN=%d ID=%d CHANNEL=%d from SCSI layer\n",(int)srb->device->lun,(int)srb->device->id, (int)srb->device->channel ); MTS_DEBUG("this device doesn't exist\n"); srb->result = DID_BAD_TARGET << 16; if(callback) callback(srb); goto out; } FILL_BULK_URB(&desc->urb, desc->usb_dev, usb_sndbulkpipe(desc->usb_dev,desc->ep_out), srb->cmnd, srb->cmd_len, mts_command_done, &desc->context ); mts_build_transfer_context( srb, desc ); desc->context.final_callback = callback; res=usb_submit_urb(&desc->urb); if(res){ MTS_ERROR("error %d submitting URB\n",(int)res); srb->result = DID_ERROR << 16; if(callback) callback(srb); }out: return err;}/* * this defines our 'host' *//* NOTE: This is taken from usb-storage, should be right. */static Scsi_Host_Template mts_scsi_host_template = { name: "microtekX6", detect: mts_scsi_detect, release: mts_scsi_release, queuecommand: mts_scsi_queuecommand, eh_abort_handler: mts_scsi_abort, eh_host_reset_handler: mts_scsi_host_reset, sg_tablesize: SG_ALL, can_queue: 1, this_id: -1, cmd_per_lun: 1, present: 0, unchecked_isa_dma: FALSE, use_clustering: TRUE, use_new_eh_code: TRUE, emulated: TRUE};/* USB layer driver interface implementation */static void mts_usb_disconnect (struct usb_device *dev, void *ptr){ struct mts_desc* to_remove = (struct mts_desc*)ptr; MTS_DEBUG_GOT_HERE(); /* leave the list - lock it */ down(&mts_list_semaphore); mts_remove_nolock(to_remove); up(&mts_list_semaphore);}struct vendor_product{ char* name; enum { mts_sup_unknown=0, mts_sup_alpha, mts_sup_full } support_status;} ;/* These are taken from the msmUSB.inf file on the Windows driver CD */const static struct vendor_product mts_supported_products[] ={ { "Phantom 336CX", mts_sup_unknown}, { "Phantom 336CX", mts_sup_unknown}, { "Scanmaker X6", mts_sup_alpha}, { "Phantom C6", mts_sup_unknown}, { "Phantom 336CX", mts_sup_unknown}, { "ScanMaker V6USL", mts_sup_unknown}, { "ScanMaker V6USL", mts_sup_unknown}, { "Scanmaker V6UL", mts_sup_unknown}, { "Scanmaker V6UPL", mts_sup_alpha},};/* The entries of microtek_table must correspond, line-by-line to the entries of mts_supported_products[]. */static struct usb_device_id mts_usb_ids [] ={ { USB_DEVICE(0x4ce, 0x0300) }, { USB_DEVICE(0x5da, 0x0094) }, { USB_DEVICE(0x5da, 0x0099) }, { USB_DEVICE(0x5da, 0x009a) }, { USB_DEVICE(0x5da, 0x00a0) }, { USB_DEVICE(0x5da, 0x00a3) }, { USB_DEVICE(0x5da, 0x80a3) }, { USB_DEVICE(0x5da, 0x80ac) }, { USB_DEVICE(0x5da, 0x00b6) }, { } /* Terminating entry */};MODULE_DEVICE_TABLE (usb, mts_usb_ids);static void * mts_usb_probe (struct usb_device *dev, unsigned int interface, const struct usb_device_id *id){ int i; int result; int ep_out = -1; int ep_in_set[3]; /* this will break if we have more than three endpoints which is why we check */ int *ep_in_current = ep_in_set; struct mts_desc * new_desc; struct vendor_product const* p; /* the altsettting 0 on the interface we're probing */ struct usb_interface_descriptor *altsetting; MTS_DEBUG_GOT_HERE(); MTS_DEBUG( "usb-device descriptor at %x\n", (int)dev ); MTS_DEBUG( "product id = 0x%x, vendor id = 0x%x\n", (int)dev->descriptor.idProduct, (int)dev->descriptor.idVendor ); MTS_DEBUG_GOT_HERE(); p = &mts_supported_products[id - mts_usb_ids]; MTS_DEBUG_GOT_HERE(); MTS_DEBUG( "found model %s\n", p->name ); if ( p->support_status != mts_sup_full ) MTS_MESSAGE( "model %s is not known to be fully supported, reports welcome!\n", p->name ); /* the altsettting 0 on the interface we're probing */ altsetting = &(dev->actconfig->interface[interface].altsetting[0]); /* Check if the config is sane */ if ( altsetting->bNumEndpoints != MTS_EP_TOTAL ) { MTS_WARNING( "expecting %d got %d endpoints! Bailing out.\n", (int)MTS_EP_TOTAL, (int)altsetting->bNumEndpoints ); return NULL; } for( i = 0; i < altsetting->bNumEndpoints; i++ ) { if ((altsetting->endpoint[i].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK) { MTS_WARNING( "can only deal with bulk endpoints; endpoint %d is not bulk.\n", (int)altsetting->endpoint[i].bEndpointAddress ); } else { if (altsetting->endpoint[i].bEndpointAddress & USB_DIR_IN) *ep_in_current++ = altsetting->endpoint[i].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; else { if ( ep_out != -1 ) { MTS_WARNING( "can only deal with one output endpoints. Bailing out." ); return NULL; } ep_out = altsetting->endpoint[i].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; } } } if ( ep_out == -1 ) { MTS_WARNING( "couldn't find an output bulk endpoint. Bailing out.\n" ); return NULL; } /* I don't understand the following fully (it's from usb-storage) -- John */ /* set the interface -- STALL is an acceptable response here */ result = usb_set_interface(dev, altsetting->bInterfaceNumber, 0); MTS_DEBUG("usb_set_interface returned %d.\n",result); switch( result ) { case 0: /* no error */ break; case -EPIPE: usb_clear_halt(dev, usb_sndctrlpipe(dev, 0)); MTS_DEBUG( "clearing clearing stall on control interface\n" ); break; default: MTS_DEBUG( "unknown error %d from usb_set_interface\n", (int)result ); return NULL; } /* allocating a new descriptor */ new_desc = (struct mts_desc *)kmalloc(sizeof(struct mts_desc), GFP_KERNEL); if (new_desc == NULL) { MTS_ERROR("couldn't allocate scanner desc, bailing out!\n"); return NULL; } /* As done by usb_alloc_urb */ memset( new_desc, 0, sizeof(*new_desc) ); spin_lock_init(&new_desc->urb.lock); /* initialising that descriptor */ new_desc->usb_dev = dev; new_desc->interface = interface; init_MUTEX(&new_desc->lock); if(mts_list){ new_desc->host_number = mts_list->host_number+1; } else { new_desc->host_number = 0; } /* endpoints */ new_desc->ep_out = ep_out; new_desc->ep_response = ep_in_set[0]; new_desc->ep_image = ep_in_set[1]; if ( new_desc->ep_out != MTS_EP_OUT ) MTS_WARNING( "will this work? Command EP is not usually %d\n", (int)new_desc->ep_out ); if ( new_desc->ep_response != MTS_EP_RESPONSE ) MTS_WARNING( "will this work? Response EP is not usually %d\n", (int)new_desc->ep_response ); if ( new_desc->ep_image != MTS_EP_IMAGE ) MTS_WARNING( "will this work? Image data EP is not usually %d\n", (int)new_desc->ep_image ); /* Initialize the host template based on the default one */ memcpy(&(new_desc->ctempl), &mts_scsi_host_template, sizeof(mts_scsi_host_template)); /* HACK from usb-storage - this is needed for scsi detection */ (struct mts_desc *)new_desc->ctempl.proc_dir = new_desc; /* FIXME */ MTS_DEBUG("registering SCSI module\n"); new_desc->ctempl.module = THIS_MODULE; result = scsi_register_module(MODULE_SCSI_HA, &(new_desc->ctempl)); /* Will get hit back in microtek_detect by this func */ if ( result ) { MTS_ERROR( "error %d from scsi_register_module! Help!\n", (int)result ); /* FIXME: need more cleanup? */ kfree( new_desc ); return NULL; } MTS_DEBUG_GOT_HERE(); /* FIXME: the bomb is armed, must the host be registered under lock ? */ /* join the list - lock it */ down(&mts_list_semaphore); mts_add_nolock( new_desc ); up(&mts_list_semaphore); MTS_DEBUG("completed probe and exiting happily\n"); return (void *)new_desc;}/* get us noticed by the rest of the kernel */int __init microtek_drv_init(void){ int result; MTS_DEBUG_GOT_HERE(); init_MUTEX(&mts_list_semaphore); if ((result = usb_register(&mts_usb_driver)) < 0) { MTS_DEBUG("usb_register returned %d\n", result ); return -1; } else { MTS_DEBUG("driver registered.\n"); } info(DRIVER_VERSION ":" DRIVER_DESC); return 0;}void __exit microtek_drv_exit(void){ struct mts_desc* next; MTS_DEBUG_GOT_HERE(); usb_deregister(&mts_usb_driver); down(&mts_list_semaphore); while (mts_list) { /* keep track of where the next one is */ next = mts_list->next; mts_remove_nolock( mts_list ); /* advance the list pointer */ mts_list = next; } up(&mts_list_semaphore);}module_init(microtek_drv_init);module_exit(microtek_drv_exit);MODULE_AUTHOR( DRIVER_AUTHOR );MODULE_DESCRIPTION( DRIVER_DESC );MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -