]> sigrok.org Git - libsigrok.git/blame - hardware/openbench-logic-sniffer/api.c
Eliminate internal usage of serial->fd in serial.c.
[libsigrok.git] / hardware / openbench-logic-sniffer / api.c
CommitLineData
0aba65da 1/*
50985c20 2 * This file is part of the libsigrok project.
0aba65da 3 *
13d8e03c 4 * Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
0aba65da
UH
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * 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
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include "protocol.h"
21
22#define SERIALCOMM "115200/8n1"
23
e46aa4f6 24static const int32_t hwopts[] = {
1953564a
BV
25 SR_CONF_CONN,
26 SR_CONF_SERIALCOMM,
aeabd308
UH
27};
28
e46aa4f6 29static const int32_t hwcaps[] = {
1953564a
BV
30 SR_CONF_LOGIC_ANALYZER,
31 SR_CONF_SAMPLERATE,
0c05591a 32 SR_CONF_TRIGGER_TYPE,
1953564a
BV
33 SR_CONF_CAPTURE_RATIO,
34 SR_CONF_LIMIT_SAMPLES,
eb1b610b 35 SR_CONF_EXTERNAL_CLOCK,
967760a8 36 SR_CONF_PATTERN_MODE,
7b0a57fd 37 SR_CONF_SWAP,
1953564a 38 SR_CONF_RLE,
0aba65da
UH
39};
40
967760a8
MR
41#define STR_PATTERN_EXTERNAL "external"
42#define STR_PATTERN_INTERNAL "internal"
43
44/* Supported methods of test pattern outputs */
45enum {
46 /**
47 * Capture pins 31:16 (unbuffered wing) output a test pattern
48 * that can captured on pins 0:15.
49 */
50 PATTERN_EXTERNAL,
51
52 /** Route test pattern internally to capture buffer. */
53 PATTERN_INTERNAL,
54};
55
7c07a178
UH
56static const char *patterns[] = {
57 STR_PATTERN_EXTERNAL,
58 STR_PATTERN_INTERNAL,
59};
60
0aba65da
UH
61/* Probes are numbered 0-31 (on the PCB silkscreen). */
62SR_PRIV const char *ols_probe_names[NUM_PROBES + 1] = {
78693401
UH
63 "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12",
64 "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23",
65 "24", "25", "26", "27", "28", "29", "30", "31",
0aba65da
UH
66 NULL,
67};
68
d3b38ad3 69/* Default supported samplerates, can be overridden by device metadata. */
e46aa4f6
BV
70static const uint64_t samplerates[] = {
71 SR_HZ(10),
72 SR_MHZ(200),
73 SR_HZ(1),
0aba65da
UH
74};
75
76SR_PRIV struct sr_dev_driver ols_driver_info;
77static struct sr_dev_driver *di = &ols_driver_info;
78
eea49cf1
UH
79static int dev_clear(void)
80{
81 return std_dev_clear(di, NULL);
82}
83
03f4de8c 84static int init(struct sr_context *sr_ctx)
0aba65da 85{
f6beaac5 86 return std_init(sr_ctx, di, LOG_PREFIX);
0aba65da
UH
87}
88
03f4de8c 89static GSList *scan(GSList *options)
0aba65da 90{
1987b8d6 91 struct sr_config *src;
0aba65da
UH
92 struct sr_dev_inst *sdi;
93 struct drv_context *drvc;
94 struct dev_context *devc;
95 struct sr_probe *probe;
96 struct sr_serial_dev_inst *serial;
97 GPollFD probefd;
98 GSList *l, *devices;
99 int ret, i;
100 const char *conn, *serialcomm;
101 char buf[8];
102
0aba65da 103 drvc = di->priv;
4b97c74e 104
0aba65da
UH
105 devices = NULL;
106
107 conn = serialcomm = NULL;
108 for (l = options; l; l = l->next) {
1987b8d6
BV
109 src = l->data;
110 switch (src->key) {
1953564a 111 case SR_CONF_CONN:
e46aa4f6 112 conn = g_variant_get_string(src->data, NULL);
0aba65da 113 break;
1953564a 114 case SR_CONF_SERIALCOMM:
e46aa4f6 115 serialcomm = g_variant_get_string(src->data, NULL);
0aba65da
UH
116 break;
117 }
118 }
119 if (!conn)
120 return NULL;
121
122 if (serialcomm == NULL)
123 serialcomm = SERIALCOMM;
124
125 if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
126 return NULL;
127
128 /* The discovery procedure is like this: first send the Reset
129 * command (0x00) 5 times, since the device could be anywhere
130 * in a 5-byte command. Then send the ID command (0x02).
131 * If the device responds with 4 bytes ("OLS1" or "SLA1"), we
132 * have a match.
133 */
134 sr_info("Probing %s.", conn);
135 if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
136 return NULL;
137
138 ret = SR_OK;
139 for (i = 0; i < 5; i++) {
140 if ((ret = send_shortcommand(serial, CMD_RESET)) != SR_OK) {
141 sr_err("Port %s is not writable.", conn);
142 break;
143 }
144 }
145 if (ret != SR_OK) {
146 serial_close(serial);
147 sr_err("Could not use port %s. Quitting.", conn);
148 return NULL;
149 }
150 send_shortcommand(serial, CMD_ID);
151
152 /* Wait 10ms for a response. */
153 g_usleep(10000);
154
155 probefd.fd = serial->fd;
156 probefd.events = G_IO_IN;
157 g_poll(&probefd, 1, 1);
158
159 if (probefd.revents != G_IO_IN)
160 return NULL;
161 if (serial_read(serial, buf, 4) != 4)
162 return NULL;
163 if (strncmp(buf, "1SLO", 4) && strncmp(buf, "1ALS", 4))
164 return NULL;
165
166 /* Definitely using the OLS protocol, check if it supports
167 * the metadata command.
168 */
169 send_shortcommand(serial, CMD_METADATA);
170 if (g_poll(&probefd, 1, 10) > 0) {
171 /* Got metadata. */
172 sdi = get_metadata(serial);
173 sdi->index = 0;
174 devc = sdi->priv;
175 } else {
176 /* Not an OLS -- some other board that uses the sump protocol. */
72cd99b8 177 sr_info("Device does not support metadata.");
0aba65da
UH
178 sdi = sr_dev_inst_new(0, SR_ST_INACTIVE,
179 "Sump", "Logic Analyzer", "v1.0");
180 sdi->driver = di;
0aba65da
UH
181 for (i = 0; i < 32; i++) {
182 if (!(probe = sr_probe_new(i, SR_PROBE_LOGIC, TRUE,
183 ols_probe_names[i])))
184 return 0;
185 sdi->probes = g_slist_append(sdi->probes, probe);
186 }
bf256783 187 devc = ols_dev_new();
0aba65da
UH
188 sdi->priv = devc;
189 }
bf256783
BV
190 /* Configure samplerate and divider. */
191 if (ols_set_samplerate(sdi, DEFAULT_SAMPLERATE) != SR_OK)
192 sr_dbg("Failed to set default samplerate (%"PRIu64").",
193 DEFAULT_SAMPLERATE);
194 /* Clear trigger masks, values and stages. */
195 ols_configure_probes(sdi);
459a0f26
BV
196 sdi->inst_type = SR_INST_SERIAL;
197 sdi->conn = serial;
bf256783 198
0aba65da
UH
199 drvc->instances = g_slist_append(drvc->instances, sdi);
200 devices = g_slist_append(devices, sdi);
201
202 serial_close(serial);
203
204 return devices;
205}
206
03f4de8c 207static GSList *dev_list(void)
0aba65da 208{
0e94d524 209 return ((struct drv_context *)(di->priv))->instances;
0aba65da
UH
210}
211
03f4de8c 212static int dev_open(struct sr_dev_inst *sdi)
0aba65da 213{
459a0f26 214 struct sr_serial_dev_inst *serial;
0aba65da 215
459a0f26 216 serial = sdi->conn;
4403c39f 217 if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
0aba65da
UH
218 return SR_ERR;
219
220 sdi->status = SR_ST_ACTIVE;
221
222 return SR_OK;
223}
224
eea49cf1 225static int cleanup(void)
0aba65da 226{
eea49cf1 227 return dev_clear();
0aba65da
UH
228}
229
8f996b89
ML
230static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi,
231 const struct sr_probe_group *probe_group)
0aba65da
UH
232{
233 struct dev_context *devc;
234
8f996b89
ML
235 (void)probe_group;
236
0c05591a
BV
237 if (!sdi)
238 return SR_ERR_ARG;
239
240 devc = sdi->priv;
035a1078 241 switch (id) {
123e1313 242 case SR_CONF_SAMPLERATE:
0c05591a
BV
243 *data = g_variant_new_uint64(devc->cur_samplerate);
244 break;
245 case SR_CONF_CAPTURE_RATIO:
246 *data = g_variant_new_uint64(devc->capture_ratio);
247 break;
248 case SR_CONF_LIMIT_SAMPLES:
249 *data = g_variant_new_uint64(devc->limit_samples);
250 break;
967760a8
MR
251 case SR_CONF_PATTERN_MODE:
252 if (devc->flag_reg & FLAG_EXTERNAL_TEST_MODE)
253 *data = g_variant_new_string(STR_PATTERN_EXTERNAL);
254 else if (devc->flag_reg & FLAG_INTERNAL_TEST_MODE)
255 *data = g_variant_new_string(STR_PATTERN_INTERNAL);
256 break;
0c05591a
BV
257 case SR_CONF_RLE:
258 *data = g_variant_new_boolean(devc->flag_reg & FLAG_RLE ? TRUE : FALSE);
0aba65da
UH
259 break;
260 default:
bd6fbf62 261 return SR_ERR_NA;
0aba65da
UH
262 }
263
264 return SR_OK;
265}
266
8f996b89
ML
267static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
268 const struct sr_probe_group *probe_group)
0aba65da
UH
269{
270 struct dev_context *devc;
271 int ret;
e46aa4f6 272 uint64_t tmp_u64;
967760a8 273 const char *stropt;
0aba65da 274
8f996b89
ML
275 (void)probe_group;
276
e73ffd42
BV
277 if (sdi->status != SR_ST_ACTIVE)
278 return SR_ERR_DEV_CLOSED;
279
0aba65da
UH
280 devc = sdi->priv;
281
035a1078 282 switch (id) {
1953564a 283 case SR_CONF_SAMPLERATE:
e46aa4f6
BV
284 tmp_u64 = g_variant_get_uint64(data);
285 if (tmp_u64 < samplerates[0] || tmp_u64 > samplerates[1])
286 return SR_ERR_SAMPLERATE;
287 ret = ols_set_samplerate(sdi, g_variant_get_uint64(data));
0aba65da 288 break;
1953564a 289 case SR_CONF_LIMIT_SAMPLES:
e46aa4f6
BV
290 tmp_u64 = g_variant_get_uint64(data);
291 if (tmp_u64 < MIN_NUM_SAMPLES)
0aba65da 292 return SR_ERR;
e46aa4f6 293 devc->limit_samples = tmp_u64;
0aba65da
UH
294 ret = SR_OK;
295 break;
1953564a 296 case SR_CONF_CAPTURE_RATIO:
e46aa4f6 297 devc->capture_ratio = g_variant_get_uint64(data);
0aba65da
UH
298 if (devc->capture_ratio < 0 || devc->capture_ratio > 100) {
299 devc->capture_ratio = 0;
300 ret = SR_ERR;
301 } else
302 ret = SR_OK;
303 break;
eb1b610b
MR
304 case SR_CONF_EXTERNAL_CLOCK:
305 if (g_variant_get_boolean(data)) {
306 sr_info("Enabling external clock.");
307 devc->flag_reg |= FLAG_CLOCK_EXTERNAL;
308 } else {
309 sr_info("Disabled external clock.");
310 devc->flag_reg &= ~FLAG_CLOCK_EXTERNAL;
311 }
312 ret = SR_OK;
313 break;
967760a8
MR
314 case SR_CONF_PATTERN_MODE:
315 stropt = g_variant_get_string(data, NULL);
316 ret = SR_OK;
317 if (!strcmp(stropt, STR_PATTERN_INTERNAL)) {
318 sr_info("Enabling internal test mode.");
319 devc->flag_reg |= FLAG_INTERNAL_TEST_MODE;
320 } else if (!strcmp(stropt, STR_PATTERN_EXTERNAL)) {
321 sr_info("Enabling external test mode.");
322 devc->flag_reg |= FLAG_EXTERNAL_TEST_MODE;
323 } else {
324 ret = SR_ERR;
325 }
326 break;
7b0a57fd
MR
327 case SR_CONF_SWAP:
328 if (g_variant_get_boolean(data)) {
329 sr_info("Enabling channel swapping.");
330 devc->flag_reg |= FLAG_SWAP_PROBES;
331 } else {
332 sr_info("Disabling channel swapping.");
333 devc->flag_reg &= ~FLAG_SWAP_PROBES;
334 }
335 ret = SR_OK;
336 break;
337
1953564a 338 case SR_CONF_RLE:
e46aa4f6 339 if (g_variant_get_boolean(data)) {
0aba65da
UH
340 sr_info("Enabling RLE.");
341 devc->flag_reg |= FLAG_RLE;
aeea0572
BV
342 } else {
343 sr_info("Disabling RLE.");
344 devc->flag_reg &= ~FLAG_RLE;
0aba65da
UH
345 }
346 ret = SR_OK;
347 break;
348 default:
bd6fbf62 349 ret = SR_ERR_NA;
0aba65da
UH
350 }
351
352 return ret;
353}
354
8f996b89
ML
355static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
356 const struct sr_probe_group *probe_group)
a1c743fc 357{
e46aa4f6
BV
358 GVariant *gvar;
359 GVariantBuilder gvb;
a1c743fc
BV
360
361 (void)sdi;
8f996b89 362 (void)probe_group;
a1c743fc
BV
363
364 switch (key) {
0d485e30 365 case SR_CONF_SCAN_OPTIONS:
e46aa4f6
BV
366 *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
367 hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
0d485e30 368 break;
9a6517d1 369 case SR_CONF_DEVICE_OPTIONS:
e46aa4f6
BV
370 *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
371 hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
9a6517d1 372 break;
a1c743fc 373 case SR_CONF_SAMPLERATE:
e46aa4f6
BV
374 g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
375 gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"), samplerates,
376 ARRAY_SIZE(samplerates), sizeof(uint64_t));
377 g_variant_builder_add(&gvb, "{sv}", "samplerate-steps", gvar);
378 *data = g_variant_builder_end(&gvb);
a1c743fc 379 break;
c50277a6 380 case SR_CONF_TRIGGER_TYPE:
e46aa4f6 381 *data = g_variant_new_string(TRIGGER_TYPE);
c50277a6 382 break;
7c07a178
UH
383 case SR_CONF_PATTERN_MODE:
384 *data = g_variant_new_strv(patterns, ARRAY_SIZE(patterns));
385 break;
a1c743fc 386 default:
bd6fbf62 387 return SR_ERR_NA;
a1c743fc
BV
388 }
389
390 return SR_OK;
391}
392
03f4de8c 393static int dev_acquisition_start(const struct sr_dev_inst *sdi,
0aba65da
UH
394 void *cb_data)
395{
0aba65da 396 struct dev_context *devc;
459a0f26 397 struct sr_serial_dev_inst *serial;
0aba65da
UH
398 uint32_t trigger_config[4];
399 uint32_t data;
400 uint16_t readcount, delaycount;
401 uint8_t changrp_mask;
402 int num_channels;
403 int i;
404
e73ffd42
BV
405 if (sdi->status != SR_ST_ACTIVE)
406 return SR_ERR_DEV_CLOSED;
407
0aba65da 408 devc = sdi->priv;
459a0f26 409 serial = sdi->conn;
0aba65da 410
0aba65da
UH
411 if (ols_configure_probes(sdi) != SR_OK) {
412 sr_err("Failed to configure probes.");
413 return SR_ERR;
414 }
415
416 /*
417 * Enable/disable channel groups in the flag register according to the
418 * probe mask. Calculate this here, because num_channels is needed
419 * to limit readcount.
420 */
421 changrp_mask = 0;
422 num_channels = 0;
423 for (i = 0; i < 4; i++) {
424 if (devc->probe_mask & (0xff << (i * 8))) {
425 changrp_mask |= (1 << i);
426 num_channels++;
427 }
428 }
429
430 /*
431 * Limit readcount to prevent reading past the end of the hardware
432 * buffer.
433 */
434 readcount = MIN(devc->max_samples / num_channels, devc->limit_samples) / 4;
435
436 memset(trigger_config, 0, 16);
2e5b73c0 437 trigger_config[devc->num_stages] |= 0x08;
0aba65da
UH
438 if (devc->trigger_mask[0]) {
439 delaycount = readcount * (1 - devc->capture_ratio / 100.0);
440 devc->trigger_at = (readcount - delaycount) * 4 - devc->num_stages;
441
459a0f26 442 if (send_longcommand(serial, CMD_SET_TRIGGER_MASK_0,
0aba65da
UH
443 reverse32(devc->trigger_mask[0])) != SR_OK)
444 return SR_ERR;
459a0f26 445 if (send_longcommand(serial, CMD_SET_TRIGGER_VALUE_0,
0aba65da
UH
446 reverse32(devc->trigger_value[0])) != SR_OK)
447 return SR_ERR;
459a0f26 448 if (send_longcommand(serial, CMD_SET_TRIGGER_CONFIG_0,
0aba65da
UH
449 trigger_config[0]) != SR_OK)
450 return SR_ERR;
451
459a0f26 452 if (send_longcommand(serial, CMD_SET_TRIGGER_MASK_1,
0aba65da
UH
453 reverse32(devc->trigger_mask[1])) != SR_OK)
454 return SR_ERR;
459a0f26 455 if (send_longcommand(serial, CMD_SET_TRIGGER_VALUE_1,
0aba65da
UH
456 reverse32(devc->trigger_value[1])) != SR_OK)
457 return SR_ERR;
459a0f26 458 if (send_longcommand(serial, CMD_SET_TRIGGER_CONFIG_1,
0aba65da
UH
459 trigger_config[1]) != SR_OK)
460 return SR_ERR;
461
459a0f26 462 if (send_longcommand(serial, CMD_SET_TRIGGER_MASK_2,
0aba65da
UH
463 reverse32(devc->trigger_mask[2])) != SR_OK)
464 return SR_ERR;
459a0f26 465 if (send_longcommand(serial, CMD_SET_TRIGGER_VALUE_2,
0aba65da
UH
466 reverse32(devc->trigger_value[2])) != SR_OK)
467 return SR_ERR;
459a0f26 468 if (send_longcommand(serial, CMD_SET_TRIGGER_CONFIG_2,
0aba65da
UH
469 trigger_config[2]) != SR_OK)
470 return SR_ERR;
471
459a0f26 472 if (send_longcommand(serial, CMD_SET_TRIGGER_MASK_3,
0aba65da
UH
473 reverse32(devc->trigger_mask[3])) != SR_OK)
474 return SR_ERR;
459a0f26 475 if (send_longcommand(serial, CMD_SET_TRIGGER_VALUE_3,
0aba65da
UH
476 reverse32(devc->trigger_value[3])) != SR_OK)
477 return SR_ERR;
459a0f26 478 if (send_longcommand(serial, CMD_SET_TRIGGER_CONFIG_3,
0aba65da
UH
479 trigger_config[3]) != SR_OK)
480 return SR_ERR;
481 } else {
459a0f26 482 if (send_longcommand(serial, CMD_SET_TRIGGER_MASK_0,
0aba65da
UH
483 devc->trigger_mask[0]) != SR_OK)
484 return SR_ERR;
459a0f26 485 if (send_longcommand(serial, CMD_SET_TRIGGER_VALUE_0,
0aba65da
UH
486 devc->trigger_value[0]) != SR_OK)
487 return SR_ERR;
459a0f26 488 if (send_longcommand(serial, CMD_SET_TRIGGER_CONFIG_0,
0aba65da
UH
489 0x00000008) != SR_OK)
490 return SR_ERR;
491 delaycount = readcount;
492 }
493
494 sr_info("Setting samplerate to %" PRIu64 "Hz (divider %u, "
de524099
MR
495 "demux %s, noise_filter %s)", devc->cur_samplerate,
496 devc->cur_samplerate_divider,
497 devc->flag_reg & FLAG_DEMUX ? "on" : "off",
498 devc->flag_reg & FLAG_FILTER ? "on": "off");
459a0f26 499 if (send_longcommand(serial, CMD_SET_DIVIDER,
0aba65da
UH
500 reverse32(devc->cur_samplerate_divider)) != SR_OK)
501 return SR_ERR;
502
503 /* Send sample limit and pre/post-trigger capture ratio. */
504 data = ((readcount - 1) & 0xffff) << 16;
505 data |= (delaycount - 1) & 0xffff;
459a0f26 506 if (send_longcommand(serial, CMD_CAPTURE_SIZE, reverse16(data)) != SR_OK)
0aba65da
UH
507 return SR_ERR;
508
509 /* The flag register wants them here, and 1 means "disable channel". */
510 devc->flag_reg |= ~(changrp_mask << 2) & 0x3c;
0aba65da
UH
511 devc->rle_count = 0;
512 data = (devc->flag_reg << 24) | ((devc->flag_reg << 8) & 0xff0000);
459a0f26 513 if (send_longcommand(serial, CMD_SET_FLAGS, data) != SR_OK)
0aba65da
UH
514 return SR_ERR;
515
516 /* Start acquisition on the device. */
459a0f26 517 if (send_shortcommand(serial, CMD_RUN) != SR_OK)
0aba65da
UH
518 return SR_ERR;
519
bf256783
BV
520 /* Reset all operational states. */
521 devc->num_transfers = devc->num_samples = devc->num_bytes = 0;
abb39e6b 522 memset(devc->sample, 0, 4);
bf256783 523
4afdfd46 524 /* Send header packet to the session bus. */
29a27196 525 std_session_send_df_header(cb_data, LOG_PREFIX);
4afdfd46 526
abc4b335 527 serial_source_add(serial, G_IO_IN, -1, ols_receive_data, cb_data);
0aba65da 528
0aba65da
UH
529 return SR_OK;
530}
531
03f4de8c 532static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
0aba65da 533{
0aba65da
UH
534 (void)cb_data;
535
536 abort_acquisition(sdi);
537
538 return SR_OK;
539}
540
541SR_PRIV struct sr_dev_driver ols_driver_info = {
542 .name = "ols",
543 .longname = "Openbench Logic Sniffer",
544 .api_version = 1,
03f4de8c 545 .init = init,
eea49cf1 546 .cleanup = cleanup,
03f4de8c
BV
547 .scan = scan,
548 .dev_list = dev_list,
549 .dev_clear = dev_clear,
035a1078
BV
550 .config_get = config_get,
551 .config_set = config_set,
a1c743fc 552 .config_list = config_list,
03f4de8c 553 .dev_open = dev_open,
bf2c987f 554 .dev_close = std_serial_dev_close,
03f4de8c
BV
555 .dev_acquisition_start = dev_acquisition_start,
556 .dev_acquisition_stop = dev_acquisition_stop,
0aba65da
UH
557 .priv = NULL,
558};