2 * cbi.c - USB driver stack project for Windows NT 4.0
4 * Copyright (c) 2002-2004 Zhiming mypublic99@yahoo.com
6 * This program/include file is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as published
8 * by the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program/include file is distributed in the hope that it will be
12 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along with
17 * this program (in the main directory of the distribution, the file
18 * COPYING); if not, write to the Free Software Foundation,Inc., 59 Temple
19 * Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "usbdriver.h"
24 VOID
umss_cbi_send_adsc_complete(PURB purb
, PVOID context
);
25 VOID
umss_cbi_transfer_data(PUMSS_DEVICE_EXTENSION pdev_ext
);
26 VOID
umss_cbi_get_status(PUMSS_DEVICE_EXTENSION pdev_ext
);
27 VOID
umss_cbi_transfer_data_complete(PURB purb
, PVOID context
);
28 VOID
umss_cbi_get_status_complete(PURB purb
, PVOID context
);
31 umss_class_specific_request(IN PUMSS_DEVICE_EXTENSION pdev_ext
,
35 IN ULONG buffer_length
,
36 IN PURBCOMPLETION completion
)
41 UNREFERENCED_PARAMETER(dir
);
43 purb
= usb_alloc_mem(NonPagedPool
, sizeof(URB
));
44 if (!purb
) return STATUS_NO_MEMORY
;
46 // Build URB for the ADSC command
47 UsbBuildVendorRequest(purb
,
48 pdev_ext
->dev_handle
| 0xffff,
51 0x21, request
, 0, pdev_ext
->pif_desc
->bInterfaceNumber
, completion
, pdev_ext
, 0);
53 status
= usb_submit_urb(pdev_ext
->dev_mgr
, purb
);
54 if (status
!= STATUS_PENDING
)
60 dev_mgr_register_irp(pdev_ext
->dev_mgr
, pdev_ext
->io_packet
.pirp
, purb
);
65 umss_cbi_startio(IN PUMSS_DEVICE_EXTENSION pdev_ext
, IN PIO_PACKET io_packet
)
69 status
= STATUS_NOT_SUPPORTED
;
72 RtlCopyMemory(&pdev_ext
->io_packet
, io_packet
, sizeof(pdev_ext
->io_packet
));
74 // Send the ADSC request to the device
75 // Calls UMSS_CbiSendADSCComplete when transfer completes
76 status
= umss_class_specific_request(pdev_ext
,
77 ACCEPT_DEVICE_SPECIFIC_COMMAND
,
79 io_packet
->cdb
, io_packet
->cdb_length
, umss_cbi_send_adsc_complete
);
87 umss_cbi_send_adsc_complete(PURB purb
, PVOID context
)
90 PUMSS_DEVICE_EXTENSION pdev_ext
;
93 pdev_ext
= (PUMSS_DEVICE_EXTENSION
) context
;
94 io_packet
= &pdev_ext
->io_packet
;
96 status
= purb
->status
;
98 dev_mgr_remove_irp(pdev_ext
->dev_mgr
, pdev_ext
->io_packet
.pirp
);
100 if (!usb_success(status
))
102 usb_dbg_print(DBGLVL_MINIMUM
, ("umss_cbi_send_adsc_complete(): Command Block Failure!!!\n"));
104 // BUGBUG - Should reset device here?
105 // Device failed Command Block, complete with error
106 umss_complete_request(pdev_ext
, STATUS_IO_DEVICE_ERROR
);
109 else if (io_packet
->data_length
)
112 usb_dbg_print(DBGLVL_HIGH
, ("umss_cbi_send_adsc_complete(): Queuing Data Transfer DPC\n"));
113 umss_cbi_transfer_data(pdev_ext
);
116 else if (pdev_ext
->pif_desc
->bInterfaceProtocol
== PROTOCOL_CBI
)
118 // Device supports interrupt pipe, so get status
119 umss_cbi_get_status(pdev_ext
);
123 // Device does not report status, so complete request
124 umss_complete_request(pdev_ext
, STATUS_SUCCESS
);
134 umss_cbi_reset_pipe(IN PVOID reference
)
136 PUMSS_DEVICE_EXTENSION pdev_ext
;
137 pdev_ext
= (PUMSS_DEVICE_EXTENSION
) reference
;
139 // Reset the appropriate pipe, based on data direction
140 umss_reset_pipe(pdev_ext
,
141 (pdev_ext
->io_packet
.flags
& USB_DIR_IN
) ?
142 usb_make_handle((pdev_ext
->dev_handle
>> 16), pdev_ext
->if_idx
, pdev_ext
->in_endp_idx
) :
143 usb_make_handle((pdev_ext
->dev_handle
>> 16), pdev_ext
->if_idx
, pdev_ext
->out_endp_idx
));
145 // Device stalled endpoint, so complete I/O operation with error.
146 // BUGBUG is this correct? Check spec...
147 umss_complete_request(pdev_ext
, USB_STATUS_STALL_PID
);
151 umss_cbi_transfer_data(PUMSS_DEVICE_EXTENSION pdev_ext
)
156 // Get next data buffer element, if any.
157 buffer
= umss_get_buffer(pdev_ext
, &buffer_length
);
160 //Done with data phase, so move to status phase if (supported)
162 if (pdev_ext
->pif_desc
->bInterfaceProtocol
== PROTOCOL_CBI
)
164 // Device supports interrupt pipe, so get status
165 umss_cbi_get_status(pdev_ext
);
169 // No interrupt pipe, so just complete the request
170 umss_complete_request(pdev_ext
, STATUS_SUCCESS
);
175 // Transfer next element of the data phase
176 umss_bulk_transfer(pdev_ext
,
177 (UCHAR
) ((pdev_ext
->io_packet
.flags
& USB_DIR_IN
) ? USB_DIR_IN
: USB_DIR_OUT
),
178 buffer
, buffer_length
, umss_cbi_transfer_data_complete
);
184 umss_cbi_transfer_data_complete(PURB purb
, PVOID context
)
187 PUMSS_DEVICE_EXTENSION pdev_ext
;
189 pdev_ext
= (PUMSS_DEVICE_EXTENSION
) context
;
190 status
= purb
->status
;
195 if (!usb_success(status
))
197 // Device failed Data Transfer
198 // Check if we need to clear stalled pipe
199 if (usb_halted(status
))
201 // Reset pipe can only be done at passive level, so we need
202 // to schedule a work item to do it.
203 if (!umss_schedule_workitem
204 ((PVOID
) pdev_ext
, umss_cbi_reset_pipe
, pdev_ext
->dev_mgr
, pdev_ext
->dev_handle
))
206 usb_dbg_print(DBGLVL_MINIMUM
,
207 ("umss_cbi_transfer_data_complete(): Failed to allocate work-item to reset pipe!\n"));
209 umss_complete_request(pdev_ext
, STATUS_IO_DEVICE_ERROR
);
214 umss_complete_request(pdev_ext
, STATUS_IO_DEVICE_ERROR
);
218 // Transfer succeeded
219 // umss_cbi_transfer_data( pdev_ext );
220 umss_complete_request(pdev_ext
, STATUS_SUCCESS
);
226 umss_cbi_get_status(PUMSS_DEVICE_EXTENSION pdev_ext
)
231 purb
= usb_alloc_mem(NonPagedPool
, sizeof(URB
));
235 // Build a URB for our interrupt transfer
236 UsbBuildInterruptOrBulkTransferRequest(purb
,
237 usb_make_handle((pdev_ext
->dev_handle
>> 16), pdev_ext
->if_idx
,
238 pdev_ext
->int_endp_idx
), (PUCHAR
) & pdev_ext
->idb
,
239 sizeof(INTERRUPT_DATA_BLOCK
), umss_cbi_get_status_complete
,
242 // Call USB driver stack
243 status
= usb_submit_urb(pdev_ext
->dev_mgr
, purb
);
244 if (status
!= STATUS_PENDING
)
250 dev_mgr_register_irp(pdev_ext
->dev_mgr
, pdev_ext
->io_packet
.pirp
, purb
);
256 umss_cbi_get_status_complete(PURB purb
, PVOID context
)
259 PUMSS_DEVICE_EXTENSION pdev_ext
;
260 PINTERRUPT_DATA_BLOCK idb
;
262 pdev_ext
= (PUMSS_DEVICE_EXTENSION
) context
;
264 status
= purb
->status
;
265 dev_mgr_remove_irp(pdev_ext
->dev_mgr
, pdev_ext
->io_packet
.pirp
);
270 if (!usb_success(status
))
272 // Device failed Data Transfer
273 // Check if we need to clear stalled pipe
274 if (usb_halted(status
))
276 if (!umss_schedule_workitem
277 ((PVOID
) pdev_ext
, umss_cbi_reset_pipe
, pdev_ext
->dev_mgr
, pdev_ext
->dev_handle
))
279 usb_dbg_print(DBGLVL_MINIMUM
,
280 ("umss_cbi_get_status_complete(): Failed to allocate work-item to reset pipe!\n"));
282 umss_complete_request(pdev_ext
, STATUS_IO_DEVICE_ERROR
);
286 umss_complete_request(pdev_ext
, STATUS_IO_DEVICE_ERROR
);
290 // Interrupt transfer succeeded
291 idb
= &(pdev_ext
->idb
);
293 // Check for an error in the status block
294 if ((0 != idb
->bType
) || (0 != (idb
->bValue
& 0x3)))
296 umss_complete_request(pdev_ext
, STATUS_IO_DEVICE_ERROR
);
300 umss_complete_request(pdev_ext
, STATUS_SUCCESS
);