Download
jcs
/wifi_da
/scsi.c
(View History)
jcs *: Make some warnings less warny | Latest amendment: 22 on 2023-10-25 |
1 | /* |
2 | * Copyright (c) 2023 joshua stein <jcs@jcs.org> |
3 | * |
4 | * Permission to use, copy, modify, and distribute this software for any |
5 | * purpose with or without fee is hereby granted, provided that the above |
6 | * copyright notice and this permission notice appear in all copies. |
7 | * |
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
15 | */ |
16 | |
17 | #include <SCSI.h> |
18 | #include <string.h> |
19 | #include <stdio.h> |
20 | #include "wi-fi.h" |
21 | |
22 | struct scsi_inquiry { |
23 | unsigned char deviceType; |
24 | unsigned char deviceQualifier; |
25 | unsigned char version; |
26 | unsigned char responseFormat; |
27 | unsigned char additionalLength; |
28 | unsigned char vendor; |
29 | short reserved; |
30 | unsigned char vendorID[8]; |
31 | unsigned char productID[16]; |
32 | unsigned char revision[4]; |
33 | unsigned char vendor2[20]; |
34 | unsigned char reserved2[42]; |
35 | unsigned char vendor3[158]; |
36 | }; |
37 | |
38 | enum { |
39 | SCSI_READ, |
40 | SCSI_WRITE |
41 | }; |
42 | |
43 | unsigned char scsi_data[2048]; |
44 | struct SCSIInstr tib[2]; |
45 | |
46 | short scsi_io(unsigned short scsi_id, unsigned char *cdb, |
47 | unsigned long cdb_len, short io_type, unsigned long len); |
48 | |
49 | short |
50 | scsi_find_wifi(void) |
51 | { |
52 | struct scsi_inquiry inq; |
53 | short scsi_stat, scsi_msg; |
54 | unsigned char cdb[16] = { 0 }; |
55 | short i, scsi_id; |
56 | |
57 | cdb[0] = 0x12; /* inquiry */ |
58 | cdb[4] = 5; /* length */ |
59 | |
60 | tib[0].scOpcode = scNoInc; |
61 | tib[0].scParam1 = (unsigned long)&inq; |
62 | tib[0].scParam2 = 5; |
63 | tib[1].scOpcode = scStop; |
64 | tib[1].scParam1 = 0; |
65 | tib[1].scParam2 = 0; |
66 | |
67 | SCSIReset(); |
68 | |
69 | for (scsi_id = 0; scsi_id <= 7; scsi_id++) { |
70 | for (i = 0; i <= 1; i++) { |
71 | if (SCSIGet() != noErr) |
72 | goto scan_failed; |
73 | |
74 | if (SCSISelect(scsi_id) != noErr) |
75 | break; |
76 | |
77 | if (SCSICmd((Ptr)&cdb, 6) != noErr) { |
78 | SCSIComplete(&scsi_stat, &scsi_msg, 300); |
79 | goto scan_failed; |
80 | } |
81 | |
82 | memset(&inq, 0, sizeof(inq)); |
83 | |
84 | if (SCSIRead((Ptr)&tib) != noErr) { |
85 | SCSIComplete(&scsi_stat, &scsi_msg, 300); |
86 | goto scan_failed; |
87 | } |
88 | |
89 | if (i == 0) { |
90 | cdb[4] += inq.additionalLength; |
91 | tib[0].scParam2 += inq.additionalLength; |
92 | } |
93 | |
94 | if (SCSIComplete(&scsi_stat, &scsi_msg, 300) != noErr) |
95 | goto scan_failed; |
96 | |
97 | if (i == 0) |
98 | /* re-inquire with full length */ |
99 | continue; |
100 | |
101 | inq.vendorID[sizeof(inq.vendorID) - 1] = '\0'; |
102 | inq.productID[sizeof(inq.productID) - 1] = '\0'; |
103 | DEBUG_LOG(("scsi[%d]: v \"%s\", p \"%s\"", scsi_id, |
104 | inq.vendorID, inq.productID)); |
105 | |
106 | if (memcmp(inq.vendorID, "Dayna", 5) != 0 || |
107 | memcmp(inq.productID, "SCSI/Link", 9) != 0) |
108 | break; |
109 | |
110 | if (scsi_wifi_info(scsi_id, NULL)) |
111 | return scsi_id; |
112 | |
113 | DEBUG_LOG(("scsi[%d]: matched vendor/product but no info", |
114 | scsi_id)); |
115 | } |
116 | } |
117 | |
118 | scan_failed: |
119 | return WIFI_SCSI_ID_NONE; |
120 | } |
121 | |
122 | bool |
123 | scsi_wifi_scan(short scsi_id) |
124 | { |
125 | unsigned char cdb[6]; |
126 | |
127 | memset(wifi_scan_networks, 0, sizeof(wifi_scan_networks)); |
128 | |
129 | memset(cdb, 0, sizeof(cdb)); |
130 | cdb[0] = BLUESCSI_NETWORK_WIFI_CMD; |
131 | cdb[1] = BLUESCSI_NETWORK_WIFI_CMD_SCAN; |
132 | cdb[4] = 0x01; |
133 | |
134 | wifi_scan_started = Time; |
135 | |
136 | return (scsi_io(scsi_id, cdb, sizeof(cdb), SCSI_READ, 1) != -1); |
137 | } |
138 | |
139 | bool |
140 | scsi_wifi_scan_finished(short scsi_id) |
141 | { |
142 | unsigned char cdb[6]; |
143 | |
144 | memset(cdb, 0, sizeof(cdb)); |
145 | cdb[0] = BLUESCSI_NETWORK_WIFI_CMD; |
146 | cdb[1] = BLUESCSI_NETWORK_WIFI_CMD_COMPLETE; |
147 | cdb[4] = 0x01; |
148 | |
149 | if (scsi_io(scsi_id, cdb, sizeof(cdb), SCSI_READ, 1) == -1) |
150 | return true; |
151 | |
152 | if (scsi_data[0] == 1) |
153 | return true; |
154 | |
155 | return false; |
156 | } |
157 | |
158 | short |
159 | scsi_wifi_scan_results(short scsi_id, struct wifi_network_entry *resp, |
160 | short count) |
161 | { |
162 | unsigned char cdb[6]; |
163 | size_t size, net_count; |
164 | |
165 | memset(cdb, 0, sizeof(cdb)); |
166 | cdb[0] = BLUESCSI_NETWORK_WIFI_CMD; |
167 | cdb[1] = BLUESCSI_NETWORK_WIFI_CMD_SCAN_RESULTS; |
168 | cdb[3] = (sizeof(scsi_data) >> 8) & 0xff; |
169 | cdb[4] = sizeof(scsi_data) & 0xff; |
170 | |
171 | if (scsi_io(scsi_id, cdb, sizeof(cdb), SCSI_READ, |
172 | sizeof(scsi_data)) == -1) |
173 | return 0; |
174 | |
175 | size = (scsi_data[0] << 8) | scsi_data[1]; |
176 | net_count = size / sizeof(struct wifi_network_entry); |
177 | if (net_count > count) |
178 | net_count = count; |
179 | |
180 | memset(resp, 0, sizeof(struct wifi_network_entry) * count); |
181 | memcpy(resp, scsi_data + 2, sizeof(struct wifi_network_entry) * count); |
182 | |
183 | return net_count; |
184 | } |
185 | |
186 | bool |
187 | scsi_wifi_info(short scsi_id, struct wifi_network_entry *resp) |
188 | { |
189 | static struct wifi_network_entry wifi_info; |
190 | unsigned char cdb[6]; |
191 | short size; |
192 | |
193 | memset(cdb, 0, sizeof(cdb)); |
194 | cdb[0] = BLUESCSI_NETWORK_WIFI_CMD; |
195 | cdb[1] = BLUESCSI_NETWORK_WIFI_CMD_INFO; |
196 | |
197 | size = sizeof(struct wifi_network_entry) + 2; |
198 | cdb[3] = (size >> 8) & 0xff; |
199 | cdb[4] = size & 0xff; |
200 | |
201 | if (scsi_io(scsi_id, cdb, sizeof(cdb), SCSI_READ, size) == -1) |
202 | return false; |
203 | |
204 | if (resp != NULL) { |
205 | memset(resp, 0, sizeof(struct wifi_network_entry)); |
206 | /* skip returned size */ |
207 | memcpy(resp, scsi_data + 2, sizeof(struct wifi_network_entry)); |
208 | } |
209 | |
210 | return true; |
211 | } |
212 | |
213 | bool |
214 | scsi_wifi_join(short scsi_id, struct wifi_join_request *wjr) |
215 | { |
216 | unsigned char cdb[6]; |
217 | unsigned short size; |
218 | unsigned char n; |
219 | |
220 | memset(cdb, 0, sizeof(cdb)); |
221 | cdb[0] = BLUESCSI_NETWORK_WIFI_CMD; |
222 | cdb[1] = BLUESCSI_NETWORK_WIFI_CMD_JOIN; |
223 | |
224 | size = sizeof(struct wifi_join_request); |
225 | cdb[3] = (size >> 8) & 0xff; |
226 | cdb[4] = size & 0xff; |
227 | |
228 | memcpy(scsi_data, wjr, sizeof(struct wifi_join_request)); |
229 | |
230 | return (scsi_io(scsi_id, cdb, sizeof(cdb), SCSI_WRITE, size) != -1); |
231 | } |
232 | |
233 | short |
234 | scsi_io(unsigned short scsi_id, unsigned char *cdb, unsigned long cdb_len, |
235 | short io_type, unsigned long len) |
236 | { |
237 | short scsi_stat, scsi_msg; |
238 | short ret, ioret; |
239 | |
240 | if (SCSIGet() != noErr) { |
241 | warn("SCSIGet failed"); |
242 | return -1; |
243 | } |
244 | |
245 | if (SCSISelect(scsi_id) != noErr) { |
246 | warn("SCSISelect failed"); |
247 | return -1; |
248 | } |
249 | |
250 | if (SCSICmd((Ptr)cdb, cdb_len) != noErr) { |
251 | SCSIComplete(&scsi_stat, &scsi_msg, 300); |
252 | warn("SCSICmd failed"); |
253 | return -1; |
254 | } |
255 | |
256 | if (len) { |
257 | switch (io_type) { |
258 | case SCSI_READ: |
259 | memset(scsi_data, 0, sizeof(scsi_data)); |
260 | |
261 | tib[0].scOpcode = scNoInc; |
262 | tib[0].scParam1 = (long)&scsi_data; |
263 | tib[0].scParam2 = len; |
264 | tib[1].scOpcode = scStop; |
265 | tib[1].scParam1 = 0; |
266 | tib[1].scParam2 = 0; |
267 | |
268 | ioret = SCSIRead((Ptr)&tib); |
269 | break; |
270 | case SCSI_WRITE: |
271 | tib[0].scOpcode = scNoInc; |
272 | tib[0].scParam1 = (long)&scsi_data; |
273 | tib[0].scParam2 = len; |
274 | tib[1].scOpcode = scStop; |
275 | tib[1].scParam1 = 0; |
276 | tib[1].scParam2 = 0; |
277 | |
278 | ioret = SCSIWrite((Ptr)&tib); |
279 | break; |
280 | } |
281 | } else { |
282 | tib[0].scOpcode = scStop; |
283 | tib[0].scParam1 = 0; |
284 | tib[0].scParam2 = 0; |
285 | |
286 | ioret = noErr; |
287 | } |
288 | |
289 | /* complete and free the bus before responding to the read/write */ |
290 | if (SCSIComplete(&scsi_stat, &scsi_msg, 300 /* 1/60 ticks */) != noErr) { |
291 | DEBUG_LOG(("SCSIComplete failed")); |
292 | return -1; |
293 | } |
294 | |
295 | if (ioret != noErr && ioret != scPhaseErr) |
296 | DEBUG_LOG(("SCSIRead/Write failed: %d", ioret)); |
297 | |
298 | if (scsi_stat != noErr) |
299 | DEBUG_LOG(("SCSIComplete bad status: %d", scsi_stat)); |
300 | |
301 | return len; |
302 | } |