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 // Build URB for the ADSC command
45 UsbBuildVendorRequest(purb
,
46 pdev_ext
->dev_handle
| 0xffff,
49 0x21, request
, 0, pdev_ext
->pif_desc
->bInterfaceNumber
, completion
, pdev_ext
, 0);
51 status
= usb_submit_urb(pdev_ext
->dev_mgr
, purb
);
52 if (status
!= STATUS_PENDING
)
58 dev_mgr_register_irp(pdev_ext
->dev_mgr
, pdev_ext
->io_packet
.pirp
, purb
);
63 umss_cbi_startio(IN PUMSS_DEVICE_EXTENSION pdev_ext
, IN PIO_PACKET io_packet
)
67 status
= STATUS_NOT_SUPPORTED
;
70 RtlCopyMemory(&pdev_ext
->io_packet
, io_packet
, sizeof(pdev_ext
->io_packet
));
72 // Send the ADSC request to the device
73 // Calls UMSS_CbiSendADSCComplete when transfer completes
74 status
= umss_class_specific_request(pdev_ext
,
75 ACCEPT_DEVICE_SPECIFIC_COMMAND
,
77 io_packet
->cdb
, io_packet
->cdb_length
, umss_cbi_send_adsc_complete
);
85 umss_cbi_send_adsc_complete(PURB purb
, PVOID context
)
88 PUMSS_DEVICE_EXTENSION pdev_ext
;
91 pdev_ext
= (PUMSS_DEVICE_EXTENSION
) context
;
92 io_packet
= &pdev_ext
->io_packet
;
94 status
= purb
->status
;
96 dev_mgr_remove_irp(pdev_ext
->dev_mgr
, pdev_ext
->io_packet
.pirp
);
98 if (!usb_success(status
))
100 usb_dbg_print(DBGLVL_MINIMUM
, ("umss_cbi_send_adsc_complete(): Command Block Failure!!!\n"));
102 // BUGBUG - Should reset device here?
103 // Device failed Command Block, complete with error
104 umss_complete_request(pdev_ext
, STATUS_IO_DEVICE_ERROR
);
107 else if (io_packet
->data_length
)
110 usb_dbg_print(DBGLVL_HIGH
, ("umss_cbi_send_adsc_complete(): Queuing Data Transfer DPC\n"));
111 umss_cbi_transfer_data(pdev_ext
);
114 else if (pdev_ext
->pif_desc
->bInterfaceProtocol
== PROTOCOL_CBI
)
116 // Device supports interrupt pipe, so get status
117 umss_cbi_get_status(pdev_ext
);
121 // Device does not report status, so complete request
122 umss_complete_request(pdev_ext
, STATUS_SUCCESS
);
132 umss_cbi_reset_pipe(IN PVOID reference
)
134 PUMSS_DEVICE_EXTENSION pdev_ext
;
135 pdev_ext
= (PUMSS_DEVICE_EXTENSION
) reference
;
137 // Reset the appropriate pipe, based on data direction
138 umss_reset_pipe(pdev_ext
,
139 (pdev_ext
->io_packet
.flags
& USB_DIR_IN
) ?
140 usb_make_handle((pdev_ext
->dev_handle
>> 16), pdev_ext
->if_idx
, pdev_ext
->in_endp_idx
) :
141 usb_make_handle((pdev_ext
->dev_handle
>> 16), pdev_ext
->if_idx
, pdev_ext
->out_endp_idx
));
143 // Device stalled endpoint, so complete I/O operation with error.
144 // BUGBUG is this correct? Check spec...
145 umss_complete_request(pdev_ext
, USB_STATUS_STALL_PID
);
149 umss_cbi_transfer_data(PUMSS_DEVICE_EXTENSION pdev_ext
)
154 // Get next data buffer element, if any.
155 buffer
= umss_get_buffer(pdev_ext
, &buffer_length
);
158 //Done with data phase, so move to status phase if (supported)
160 if (pdev_ext
->pif_desc
->bInterfaceProtocol
== PROTOCOL_CBI
)
162 // Device supports interrupt pipe, so get status
163 umss_cbi_get_status(pdev_ext
);
167 // No interrupt pipe, so just complete the request
168 umss_complete_request(pdev_ext
, STATUS_SUCCESS
);
173 // Transfer next element of the data phase
174 umss_bulk_transfer(pdev_ext
,
175 (UCHAR
) ((pdev_ext
->io_packet
.flags
& USB_DIR_IN
) ? USB_DIR_IN
: USB_DIR_OUT
),
176 buffer
, buffer_length
, umss_cbi_transfer_data_complete
);
182 umss_cbi_transfer_data_complete(PURB purb
, PVOID context
)
185 PUMSS_DEVICE_EXTENSION pdev_ext
;
187 pdev_ext
= (PUMSS_DEVICE_EXTENSION
) context
;
188 status
= purb
->status
;
193 if (!usb_success(status
))
195 // Device failed Data Transfer
196 // Check if we need to clear stalled pipe
197 if (usb_halted(status
))
199 // Reset pipe can only be done at passive level, so we need
200 // to schedule a work item to do it.
201 if (!umss_schedule_workitem
202 ((PVOID
) pdev_ext
, umss_cbi_reset_pipe
, pdev_ext
->dev_mgr
, pdev_ext
->dev_handle
))
204 usb_dbg_print(DBGLVL_MINIMUM
,
205 ("umss_cbi_transfer_data_complete(): Failed to allocate work-item to reset pipe!\n"));
207 umss_complete_request(pdev_ext
, STATUS_IO_DEVICE_ERROR
);
212 umss_complete_request(pdev_ext
, STATUS_IO_DEVICE_ERROR
);
216 // Transfer succeeded
217 // umss_cbi_transfer_data( pdev_ext );
218 umss_complete_request(pdev_ext
, STATUS_SUCCESS
);
224 umss_cbi_get_status(PUMSS_DEVICE_EXTENSION pdev_ext
)
229 purb
= usb_alloc_mem(NonPagedPool
, sizeof(URB
));
233 // Build a URB for our interrupt transfer
234 UsbBuildInterruptOrBulkTransferRequest(purb
,
235 usb_make_handle((pdev_ext
->dev_handle
>> 16), pdev_ext
->if_idx
,
236 pdev_ext
->int_endp_idx
), (PUCHAR
) & pdev_ext
->idb
,
237 sizeof(INTERRUPT_DATA_BLOCK
), umss_cbi_get_status_complete
,
240 // Call USB driver stack
241 status
= usb_submit_urb(pdev_ext
->dev_mgr
, purb
);
242 if (status
!= STATUS_PENDING
)
248 dev_mgr_register_irp(pdev_ext
->dev_mgr
, pdev_ext
->io_packet
.pirp
, purb
);
254 umss_cbi_get_status_complete(PURB purb
, PVOID context
)
257 PUMSS_DEVICE_EXTENSION pdev_ext
;
258 PINTERRUPT_DATA_BLOCK idb
;
260 pdev_ext
= (PUMSS_DEVICE_EXTENSION
) context
;
262 status
= purb
->status
;
263 dev_mgr_remove_irp(pdev_ext
->dev_mgr
, pdev_ext
->io_packet
.pirp
);
268 if (!usb_success(status
))
270 // Device failed Data Transfer
271 // Check if we need to clear stalled pipe
272 if (usb_halted(status
))
274 if (!umss_schedule_workitem
275 ((PVOID
) pdev_ext
, umss_cbi_reset_pipe
, pdev_ext
->dev_mgr
, pdev_ext
->dev_handle
))
277 usb_dbg_print(DBGLVL_MINIMUM
,
278 ("umss_cbi_get_status_complete(): Failed to allocate work-item to reset pipe!\n"));
280 umss_complete_request(pdev_ext
, STATUS_IO_DEVICE_ERROR
);
284 umss_complete_request(pdev_ext
, STATUS_IO_DEVICE_ERROR
);
288 // Interrupt transfer succeeded
289 idb
= &(pdev_ext
->idb
);
291 // Check for an error in the status block
292 if ((0 != idb
->bType
) || (0 != (idb
->bValue
& 0x3)))
294 umss_complete_request(pdev_ext
, STATUS_IO_DEVICE_ERROR
);
298 umss_complete_request(pdev_ext
, STATUS_SUCCESS
);