Visual C++ backend for rbuild (for now just a hacked mingw backend) and related compi...
[reactos.git] / drivers / usb / nt4compat / usbdriver / cbi.c
1 /**
2 * cbi.c - USB driver stack project for Windows NT 4.0
3 *
4 * Copyright (c) 2002-2004 Zhiming mypublic99@yahoo.com
5 *
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.
10 *
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.
15 *
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
20 */
21
22 #include "usbdriver.h"
23
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);
29
30 NTSTATUS
31 umss_class_specific_request(IN PUMSS_DEVICE_EXTENSION pdev_ext,
32 IN UCHAR request,
33 IN UCHAR dir,
34 IN PVOID buffer,
35 IN ULONG buffer_length,
36 IN PURBCOMPLETION completion)
37 {
38 PURB purb;
39 NTSTATUS status;
40
41 UNREFERENCED_PARAMETER(dir);
42
43 purb = usb_alloc_mem(NonPagedPool, sizeof(URB));
44 // Build URB for the ADSC command
45 UsbBuildVendorRequest(purb,
46 pdev_ext->dev_handle | 0xffff,
47 buffer,
48 buffer_length,
49 0x21, request, 0, pdev_ext->pif_desc->bInterfaceNumber, completion, pdev_ext, 0);
50
51 status = usb_submit_urb(pdev_ext->dev_mgr, purb);
52 if (status != STATUS_PENDING)
53 {
54 usb_free_mem(purb);
55 purb = NULL;
56 return status;
57 }
58 dev_mgr_register_irp(pdev_ext->dev_mgr, pdev_ext->io_packet.pirp, purb);
59 return status;
60 }
61
62 NTSTATUS
63 umss_cbi_startio(IN PUMSS_DEVICE_EXTENSION pdev_ext, IN PIO_PACKET io_packet)
64 {
65 NTSTATUS status;
66
67 status = STATUS_NOT_SUPPORTED;
68 return status;
69
70 RtlCopyMemory(&pdev_ext->io_packet, io_packet, sizeof(pdev_ext->io_packet));
71
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,
76 USB_DIR_OUT,
77 io_packet->cdb, io_packet->cdb_length, umss_cbi_send_adsc_complete);
78
79 return status;
80 }
81
82
83
84 VOID
85 umss_cbi_send_adsc_complete(PURB purb, PVOID context)
86 {
87 NTSTATUS status;
88 PUMSS_DEVICE_EXTENSION pdev_ext;
89 PIO_PACKET io_packet;
90
91 pdev_ext = (PUMSS_DEVICE_EXTENSION) context;
92 io_packet = &pdev_ext->io_packet;
93
94 status = purb->status;
95
96 dev_mgr_remove_irp(pdev_ext->dev_mgr, pdev_ext->io_packet.pirp);
97
98 if (!usb_success(status))
99 {
100 usb_dbg_print(DBGLVL_MINIMUM, ("umss_cbi_send_adsc_complete(): Command Block Failure!!!\n"));
101
102 // BUGBUG - Should reset device here?
103 // Device failed Command Block, complete with error
104 umss_complete_request(pdev_ext, STATUS_IO_DEVICE_ERROR);
105
106 }
107 else if (io_packet->data_length)
108 {
109
110 usb_dbg_print(DBGLVL_HIGH, ("umss_cbi_send_adsc_complete(): Queuing Data Transfer DPC\n"));
111 umss_cbi_transfer_data(pdev_ext);
112
113 }
114 else if (pdev_ext->pif_desc->bInterfaceProtocol == PROTOCOL_CBI)
115 {
116 // Device supports interrupt pipe, so get status
117 umss_cbi_get_status(pdev_ext);
118 }
119 else
120 {
121 // Device does not report status, so complete request
122 umss_complete_request(pdev_ext, STATUS_SUCCESS);
123 }
124
125 usb_free_mem(purb);
126 purb = NULL;
127 }
128
129
130
131 VOID
132 umss_cbi_reset_pipe(IN PVOID reference)
133 {
134 PUMSS_DEVICE_EXTENSION pdev_ext;
135 pdev_ext = (PUMSS_DEVICE_EXTENSION) reference;
136
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));
142
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);
146 }
147
148 VOID
149 umss_cbi_transfer_data(PUMSS_DEVICE_EXTENSION pdev_ext)
150 {
151 PVOID buffer = NULL;
152 ULONG buffer_length;
153
154 // Get next data buffer element, if any.
155 buffer = umss_get_buffer(pdev_ext, &buffer_length);
156 if (NULL == buffer)
157 {
158 //Done with data phase, so move to status phase if (supported)
159
160 if (pdev_ext->pif_desc->bInterfaceProtocol == PROTOCOL_CBI)
161 {
162 // Device supports interrupt pipe, so get status
163 umss_cbi_get_status(pdev_ext);
164 }
165 else
166 {
167 // No interrupt pipe, so just complete the request
168 umss_complete_request(pdev_ext, STATUS_SUCCESS);
169 }
170 }
171 else
172 {
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);
177 }
178 }
179
180
181 VOID
182 umss_cbi_transfer_data_complete(PURB purb, PVOID context)
183 {
184 NTSTATUS status;
185 PUMSS_DEVICE_EXTENSION pdev_ext;
186
187 pdev_ext = (PUMSS_DEVICE_EXTENSION) context;
188 status = purb->status;
189
190 usb_free_mem(purb);
191 purb = NULL;
192
193 if (!usb_success(status))
194 {
195 // Device failed Data Transfer
196 // Check if we need to clear stalled pipe
197 if (usb_halted(status))
198 {
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))
203 {
204 usb_dbg_print(DBGLVL_MINIMUM,
205 ("umss_cbi_transfer_data_complete(): Failed to allocate work-item to reset pipe!\n"));
206 TRAP();
207 umss_complete_request(pdev_ext, STATUS_IO_DEVICE_ERROR);
208 }
209 }
210 else
211 {
212 umss_complete_request(pdev_ext, STATUS_IO_DEVICE_ERROR);
213 }
214 return;
215 }
216 // Transfer succeeded
217 // umss_cbi_transfer_data( pdev_ext );
218 umss_complete_request(pdev_ext, STATUS_SUCCESS);
219 return;
220 }
221
222
223 VOID
224 umss_cbi_get_status(PUMSS_DEVICE_EXTENSION pdev_ext)
225 {
226 PURB purb;
227 NTSTATUS status;
228
229 purb = usb_alloc_mem(NonPagedPool, sizeof(URB));
230 if (purb == NULL)
231 return;
232
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,
238 pdev_ext, 0);
239
240 // Call USB driver stack
241 status = usb_submit_urb(pdev_ext->dev_mgr, purb);
242 if (status != STATUS_PENDING)
243 {
244 usb_free_mem(purb);
245 purb = NULL;
246 return;
247 }
248 dev_mgr_register_irp(pdev_ext->dev_mgr, pdev_ext->io_packet.pirp, purb);
249 return;
250 }
251
252
253 VOID
254 umss_cbi_get_status_complete(PURB purb, PVOID context)
255 {
256 NTSTATUS status;
257 PUMSS_DEVICE_EXTENSION pdev_ext;
258 PINTERRUPT_DATA_BLOCK idb;
259
260 pdev_ext = (PUMSS_DEVICE_EXTENSION) context;
261
262 status = purb->status;
263 dev_mgr_remove_irp(pdev_ext->dev_mgr, pdev_ext->io_packet.pirp);
264
265 usb_free_mem(purb);
266 purb = NULL;
267
268 if (!usb_success(status))
269 {
270 // Device failed Data Transfer
271 // Check if we need to clear stalled pipe
272 if (usb_halted(status))
273 {
274 if (!umss_schedule_workitem
275 ((PVOID) pdev_ext, umss_cbi_reset_pipe, pdev_ext->dev_mgr, pdev_ext->dev_handle))
276 {
277 usb_dbg_print(DBGLVL_MINIMUM,
278 ("umss_cbi_get_status_complete(): Failed to allocate work-item to reset pipe!\n"));
279 TRAP();
280 umss_complete_request(pdev_ext, STATUS_IO_DEVICE_ERROR);
281 return;
282 }
283 }
284 umss_complete_request(pdev_ext, STATUS_IO_DEVICE_ERROR);
285 return;
286 }
287
288 // Interrupt transfer succeeded
289 idb = &(pdev_ext->idb);
290
291 // Check for an error in the status block
292 if ((0 != idb->bType) || (0 != (idb->bValue & 0x3)))
293 {
294 umss_complete_request(pdev_ext, STATUS_IO_DEVICE_ERROR);
295 }
296 else
297 {
298 umss_complete_request(pdev_ext, STATUS_SUCCESS);
299 }
300 }