]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/cam/mmc/mmc_xpt.c
Merge compiler-rt trunk r321017 to contrib/compiler-rt.
[FreeBSD/FreeBSD.git] / sys / cam / mmc / mmc_xpt.c
1 /*-
2  * Copyright (c) 2013,2014 Ilya Bakulin <ilya@bakulin.de>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer,
10  *    without modification, immediately at the beginning of the file.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <sys/param.h>
31 #include <sys/bus.h>
32 #include <sys/endian.h>
33 #include <sys/systm.h>
34 #include <sys/types.h>
35 #include <sys/malloc.h>
36 #include <sys/kernel.h>
37 #include <sys/time.h>
38 #include <sys/conf.h>
39 #include <sys/fcntl.h>
40 #include <sys/interrupt.h>
41 #include <sys/sbuf.h>
42
43 #include <sys/lock.h>
44 #include <sys/mutex.h>
45 #include <sys/sysctl.h>
46 #include <sys/condvar.h>
47
48 #include <cam/cam.h>
49 #include <cam/cam_ccb.h>
50 #include <cam/cam_queue.h>
51 #include <cam/cam_periph.h>
52 #include <cam/cam_sim.h>
53 #include <cam/cam_xpt.h>
54 #include <cam/cam_xpt_sim.h>
55 #include <cam/cam_xpt_periph.h>
56 #include <cam/cam_xpt_internal.h>
57 #include <cam/cam_debug.h>
58
59 #include <cam/mmc/mmc.h>
60 #include <cam/mmc/mmc_bus.h>
61
62 #include <machine/stdarg.h>     /* for xpt_print below */
63 #include <machine/_inttypes.h>  /* for PRIu64 */
64 #include "opt_cam.h"
65
66 FEATURE(mmccam, "CAM-based MMC/SD/SDIO stack");
67
68 static struct cam_ed * mmc_alloc_device(struct cam_eb *bus,
69     struct cam_et *target, lun_id_t lun_id);
70 static void mmc_dev_async(u_int32_t async_code, struct cam_eb *bus,
71     struct cam_et *target, struct cam_ed *device, void *async_arg);
72 static void      mmc_action(union ccb *start_ccb);
73 static void      mmc_dev_advinfo(union ccb *start_ccb);
74 static void      mmc_announce_periph(struct cam_periph *periph);
75 static void      mmc_scan_lun(struct cam_periph *periph,
76     struct cam_path *path, cam_flags flags, union ccb *ccb);
77
78 /* mmcprobe methods */
79 static cam_status mmcprobe_register(struct cam_periph *periph, void *arg);
80 static void      mmcprobe_start(struct cam_periph *periph, union ccb *start_ccb);
81 static void      mmcprobe_cleanup(struct cam_periph *periph);
82 static void      mmcprobe_done(struct cam_periph *periph, union ccb *done_ccb);
83
84 static void mmc_proto_announce(struct cam_ed *device);
85 static void mmc_proto_denounce(struct cam_ed *device);
86 static void mmc_proto_debug_out(union ccb *ccb);
87
88 typedef enum {
89         PROBE_RESET,
90         PROBE_IDENTIFY,
91         PROBE_SDIO_RESET,
92         PROBE_SEND_IF_COND,
93         PROBE_SDIO_INIT,
94         PROBE_MMC_INIT,
95         PROBE_SEND_APP_OP_COND,
96         PROBE_GET_CID,
97         PROBE_GET_CSD,
98         PROBE_SEND_RELATIVE_ADDR,
99         PROBE_SELECT_CARD,
100         PROBE_DONE,
101         PROBE_INVALID
102 } probe_action;
103
104 static char *probe_action_text[] = {
105         "PROBE_RESET",
106         "PROBE_IDENTIFY",
107         "PROBE_SDIO_RESET",
108         "PROBE_SEND_IF_COND",
109         "PROBE_SDIO_INIT",
110         "PROBE_MMC_INIT",
111         "PROBE_SEND_APP_OP_COND",
112         "PROBE_GET_CID",
113         "PROBE_GET_CSD",
114         "PROBE_SEND_RELATIVE_ADDR",
115         "PROBE_SELECT_CARD",
116         "PROBE_DONE",
117         "PROBE_INVALID"
118 };
119
120 #define PROBE_SET_ACTION(softc, newaction)      \
121 do {                                                                    \
122         char **text;                                                    \
123         text = probe_action_text;                                       \
124         CAM_DEBUG((softc)->periph->path, CAM_DEBUG_PROBE,               \
125             ("Probe %s to %s\n", text[(softc)->action],                 \
126             text[(newaction)]));                                        \
127         (softc)->action = (newaction);                                  \
128 } while(0)
129
130 static struct xpt_xport_ops mmc_xport_ops = {
131         .alloc_device = mmc_alloc_device,
132         .action = mmc_action,
133         .async = mmc_dev_async,
134         .announce = mmc_announce_periph,
135 };
136
137 #define MMC_XPT_XPORT(x, X)                             \
138         static struct xpt_xport mmc_xport_ ## x = {     \
139                 .xport = XPORT_ ## X,                   \
140                 .name = #x,                             \
141                 .ops = &mmc_xport_ops,                  \
142         };                                              \
143         CAM_XPT_XPORT(mmc_xport_ ## x);
144
145 MMC_XPT_XPORT(mmc, MMCSD);
146
147 static struct xpt_proto_ops mmc_proto_ops = {
148         .announce = mmc_proto_announce,
149         .denounce = mmc_proto_denounce,
150         .debug_out = mmc_proto_debug_out,
151 };
152
153 static struct xpt_proto mmc_proto = {
154         .proto = PROTO_MMCSD,
155         .name = "mmcsd",
156         .ops = &mmc_proto_ops,
157 };
158 CAM_XPT_PROTO(mmc_proto);
159
160 typedef struct {
161         probe_action    action;
162         int             restart;
163         union ccb       saved_ccb;
164         uint32_t        flags;
165 #define PROBE_FLAG_ACMD_SENT    0x1 /* CMD55 is sent, card expects ACMD */
166         uint8_t         acmd41_count; /* how many times ACMD41 has been issued */
167         struct cam_periph *periph;
168 } mmcprobe_softc;
169
170 /* XPort functions -- an interface to CAM at periph side */
171
172 static struct cam_ed *
173 mmc_alloc_device(struct cam_eb *bus, struct cam_et *target, lun_id_t lun_id)
174 {
175         struct cam_ed *device;
176
177         printf("mmc_alloc_device()\n");
178         device = xpt_alloc_device(bus, target, lun_id);
179         if (device == NULL)
180                 return (NULL);
181
182         device->quirk = NULL;
183         device->mintags = 0;
184         device->maxtags = 0;
185         bzero(&device->inq_data, sizeof(device->inq_data));
186         device->inq_flags = 0;
187         device->queue_flags = 0;
188         device->serial_num = NULL;
189         device->serial_num_len = 0;
190         return (device);
191 }
192
193 static void
194 mmc_dev_async(u_int32_t async_code, struct cam_eb *bus, struct cam_et *target,
195               struct cam_ed *device, void *async_arg)
196 {
197
198         printf("mmc_dev_async(async_code=0x%x, path_id=%d, target_id=%x, lun_id=%" SCNx64 "\n",
199                async_code,
200                bus->path_id,
201                target->target_id,
202                device->lun_id);
203         /*
204          * We only need to handle events for real devices.
205          */
206         if (target->target_id == CAM_TARGET_WILDCARD
207             || device->lun_id == CAM_LUN_WILDCARD)
208                 return;
209
210         if (async_code == AC_LOST_DEVICE) {
211                 if ((device->flags & CAM_DEV_UNCONFIGURED) == 0) {
212                         printf("AC_LOST_DEVICE -> set to unconfigured\n");
213                         device->flags |= CAM_DEV_UNCONFIGURED;
214                         xpt_release_device(device);
215                 } else {
216                         printf("AC_LOST_DEVICE on unconfigured device\n");
217                 }
218         } else if (async_code == AC_FOUND_DEVICE) {
219                 printf("Got AC_FOUND_DEVICE -- whatever...\n");
220         } else if (async_code == AC_PATH_REGISTERED) {
221                 printf("Got AC_PATH_REGISTERED -- whatever...\n");
222         } else if (async_code == AC_PATH_DEREGISTERED ) {
223                         printf("Got AC_PATH_DEREGISTERED -- whatever...\n");
224         } else if (async_code == AC_UNIT_ATTENTION) {
225                 printf("Got interrupt generated by the card and ignored it\n");
226         } else
227                 panic("Unknown async code\n");
228 }
229
230 /* Taken from nvme_scan_lun, thanks to bsdimp@ */
231 static void
232 mmc_scan_lun(struct cam_periph *periph, struct cam_path *path,
233              cam_flags flags, union ccb *request_ccb)
234 {
235         struct ccb_pathinq cpi;
236         cam_status status;
237         struct cam_periph *old_periph;
238         int lock;
239
240         CAM_DEBUG(path, CAM_DEBUG_TRACE, ("mmc_scan_lun\n"));
241
242         xpt_path_inq(&cpi, periph->path);
243
244         if (cpi.ccb_h.status != CAM_REQ_CMP) {
245                 if (request_ccb != NULL) {
246                         request_ccb->ccb_h.status = cpi.ccb_h.status;
247                         xpt_done(request_ccb);
248                 }
249                 return;
250         }
251
252         if (xpt_path_lun_id(path) == CAM_LUN_WILDCARD) {
253                 CAM_DEBUG(path, CAM_DEBUG_TRACE, ("mmd_scan_lun ignoring bus\n"));
254                 request_ccb->ccb_h.status = CAM_REQ_CMP;        /* XXX signal error ? */
255                 xpt_done(request_ccb);
256                 return;
257         }
258
259         lock = (xpt_path_owned(path) == 0);
260         if (lock)
261                 xpt_path_lock(path);
262
263         if ((old_periph = cam_periph_find(path, "mmcprobe")) != NULL) {
264                 if ((old_periph->flags & CAM_PERIPH_INVALID) == 0) {
265 //                      mmcprobe_softc *softc;
266 //                      softc = (mmcprobe_softc *)old_periph->softc;
267 //                      Not sure if we need request ccb queue for mmc
268 //                      TAILQ_INSERT_TAIL(&softc->request_ccbs,
269 //                              &request_ccb->ccb_h, periph_links.tqe);
270 //                      softc->restart = 1;
271                         CAM_DEBUG(path, CAM_DEBUG_INFO,
272                                   ("Got scan request, but mmcprobe already exists\n"));
273                         request_ccb->ccb_h.status = CAM_REQ_CMP_ERR;
274                         xpt_done(request_ccb);
275                 } else {
276                         request_ccb->ccb_h.status = CAM_REQ_CMP_ERR;
277                         xpt_done(request_ccb);
278                 }
279         } else {
280                 xpt_print(path, " Set up the mmcprobe device...\n");
281
282                 status = cam_periph_alloc(mmcprobe_register, NULL,
283                                           mmcprobe_cleanup,
284                                           mmcprobe_start,
285                                           "mmcprobe",
286                                           CAM_PERIPH_BIO,
287                                           path, NULL, 0,
288                                           request_ccb);
289                 if (status != CAM_REQ_CMP) {
290                         xpt_print(path, "xpt_scan_lun: cam_alloc_periph "
291                                   "returned an error, can't continue probe\n");
292                 }
293                 request_ccb->ccb_h.status = status;
294                 xpt_done(request_ccb);
295         }
296
297         if (lock)
298                 xpt_path_unlock(path);
299 }
300
301 static void
302 mmc_action(union ccb *start_ccb)
303 {
304         CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_TRACE,
305                   ("mmc_action! func_code=%x, action %s\n", start_ccb->ccb_h.func_code,
306                    xpt_action_name(start_ccb->ccb_h.func_code)));
307         switch (start_ccb->ccb_h.func_code) {
308
309         case XPT_SCAN_BUS:
310                 /* FALLTHROUGH */
311         case XPT_SCAN_TGT:
312                 /* FALLTHROUGH */
313         case XPT_SCAN_LUN:
314                 CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_INFO,
315                           ("XPT_SCAN_{BUS,TGT,LUN}\n"));
316                 mmc_scan_lun(start_ccb->ccb_h.path->periph,
317                              start_ccb->ccb_h.path, start_ccb->crcn.flags,
318                              start_ccb);
319                 break;
320
321         case XPT_DEV_ADVINFO:
322         {
323                 mmc_dev_advinfo(start_ccb);
324                 break;
325         }
326
327         default:
328                 xpt_action_default(start_ccb);
329                 break;
330         }
331 }
332
333 static void
334 mmc_dev_advinfo(union ccb *start_ccb)
335 {
336         struct cam_ed *device;
337         struct ccb_dev_advinfo *cdai;
338         off_t amt;
339
340         start_ccb->ccb_h.status = CAM_REQ_INVALID;
341         device = start_ccb->ccb_h.path->device;
342         cdai = &start_ccb->cdai;
343         CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_TRACE,
344                   ("%s: request %x\n", __func__, cdai->buftype));
345
346         /* We don't support writing any data */
347         if (cdai->flags & CDAI_FLAG_STORE)
348                 panic("Attempt to store data?!");
349
350         switch(cdai->buftype) {
351         case CDAI_TYPE_SCSI_DEVID:
352                 cdai->provsiz = device->device_id_len;
353                 if (device->device_id_len == 0)
354                         break;
355                 amt = MIN(cdai->provsiz, cdai->bufsiz);
356                 memcpy(cdai->buf, device->device_id, amt);
357                 break;
358         case CDAI_TYPE_SERIAL_NUM:
359                 cdai->provsiz = device->serial_num_len;
360                 if (device->serial_num_len == 0)
361                         break;
362                 amt = MIN(cdai->provsiz, cdai->bufsiz);
363                 memcpy(cdai->buf, device->serial_num, amt);
364                 break;
365         case CDAI_TYPE_PHYS_PATH: /* pass(4) wants this */
366                 cdai->provsiz = 0;
367                 break;
368         default:
369                 panic("Unknown buftype");
370                 return;
371         }
372         start_ccb->ccb_h.status = CAM_REQ_CMP;
373 }
374
375 static void
376 mmc_announce_periph(struct cam_periph *periph)
377 {
378         struct  ccb_pathinq cpi;
379         struct  ccb_trans_settings cts;
380         struct  cam_path *path = periph->path;
381
382         cam_periph_assert(periph, MA_OWNED);
383
384         CAM_DEBUG(periph->path, CAM_DEBUG_INFO,
385                   ("mmc_announce_periph: called\n"));
386
387         xpt_setup_ccb(&cts.ccb_h, path, CAM_PRIORITY_NORMAL);
388         cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS;
389         cts.type = CTS_TYPE_CURRENT_SETTINGS;
390         xpt_action((union ccb*)&cts);
391         if ((cts.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)
392                 return;
393         xpt_path_inq(&cpi, periph->path);
394         printf("XPT info: CLK %04X, ...\n", cts.proto_specific.mmc.ios.clock);
395 }
396
397 /* This func is called per attached device :-( */
398 void
399 mmc_print_ident(struct mmc_params *ident_data)
400 {
401         printf("Relative addr: %08x\n", ident_data->card_rca);
402         printf("Card features: <");
403         if (ident_data->card_features & CARD_FEATURE_MMC)
404                 printf("MMC ");
405         if (ident_data->card_features & CARD_FEATURE_MEMORY)
406                 printf("Memory ");
407         if (ident_data->card_features & CARD_FEATURE_SDHC)
408                 printf("High-Capacity ");
409         if (ident_data->card_features & CARD_FEATURE_SD20)
410                 printf("SD2.0-Conditions ");
411         if (ident_data->card_features & CARD_FEATURE_SDIO)
412                 printf("SDIO ");
413         printf(">\n");
414
415         if (ident_data->card_features & CARD_FEATURE_MEMORY)
416                 printf("Card memory OCR: %08x\n", ident_data->card_ocr);
417
418         if (ident_data->card_features & CARD_FEATURE_SDIO) {
419                 printf("Card IO OCR: %08x\n", ident_data->io_ocr);
420                 printf("Number of funcitions: %u\n", ident_data->sdio_func_count);
421         }
422 }
423
424 static void
425 mmc_proto_announce(struct cam_ed *device)
426 {
427         mmc_print_ident(&device->mmc_ident_data);
428 }
429
430 static void
431 mmc_proto_denounce(struct cam_ed *device)
432 {
433         mmc_print_ident(&device->mmc_ident_data);
434 }
435
436 static void
437 mmc_proto_debug_out(union ccb *ccb)
438 {
439         if (ccb->ccb_h.func_code != XPT_MMC_IO)
440                 return;
441
442         CAM_DEBUG(ccb->ccb_h.path,
443             CAM_DEBUG_CDB,("mmc_proto_debug_out\n"));
444 }
445
446 static periph_init_t probe_periph_init;
447
448 static struct periph_driver probe_driver =
449 {
450         probe_periph_init, "mmcprobe",
451         TAILQ_HEAD_INITIALIZER(probe_driver.units), /* generation */ 0,
452         CAM_PERIPH_DRV_EARLY
453 };
454
455 PERIPHDRIVER_DECLARE(mmcprobe, probe_driver);
456
457 #define CARD_ID_FREQUENCY 400000 /* Spec requires 400kHz max during ID phase. */
458
459 static void
460 probe_periph_init()
461 {
462 }
463
464 static cam_status
465 mmcprobe_register(struct cam_periph *periph, void *arg)
466 {
467         union ccb *request_ccb; /* CCB representing the probe request */
468         cam_status status;
469         mmcprobe_softc *softc;
470
471         CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("mmcprobe_register\n"));
472
473         request_ccb = (union ccb *)arg;
474         if (request_ccb == NULL) {
475                 printf("mmcprobe_register: no probe CCB, "
476                        "can't register device\n");
477                 return(CAM_REQ_CMP_ERR);
478         }
479
480         softc = (mmcprobe_softc *)malloc(sizeof(*softc), M_CAMXPT, M_NOWAIT);
481
482         if (softc == NULL) {
483                 printf("proberegister: Unable to probe new device. "
484                        "Unable to allocate softc\n");
485                 return(CAM_REQ_CMP_ERR);
486         }
487
488         softc->flags = 0;
489         softc->acmd41_count = 0;
490         periph->softc = softc;
491         softc->periph = periph;
492         softc->action = PROBE_INVALID;
493         softc->restart = 0;
494         status = cam_periph_acquire(periph);
495
496         memset(&periph->path->device->mmc_ident_data, 0, sizeof(struct mmc_params));
497         if (status != CAM_REQ_CMP) {
498                 printf("proberegister: cam_periph_acquire failed (status=%d)\n",
499                         status);
500                 return (status);
501         }
502         CAM_DEBUG(periph->path, CAM_DEBUG_PROBE, ("Probe started\n"));
503
504         if (periph->path->device->flags & CAM_DEV_UNCONFIGURED)
505                 PROBE_SET_ACTION(softc, PROBE_RESET);
506         else
507                 PROBE_SET_ACTION(softc, PROBE_IDENTIFY);
508
509         /* This will kick the ball */
510         xpt_schedule(periph, CAM_PRIORITY_XPT);
511
512         return(CAM_REQ_CMP);
513 }
514
515 static int
516 mmc_highest_voltage(uint32_t ocr)
517 {
518         int i;
519
520         for (i = MMC_OCR_MAX_VOLTAGE_SHIFT;
521             i >= MMC_OCR_MIN_VOLTAGE_SHIFT; i--)
522                 if (ocr & (1 << i))
523                         return (i);
524         return (-1);
525 }
526
527 static inline void
528 init_standard_ccb(union ccb *ccb, uint32_t cmd)
529 {
530         ccb->ccb_h.func_code = cmd;
531         ccb->ccb_h.flags = CAM_DIR_OUT;
532         ccb->ccb_h.retry_count = 0;
533         ccb->ccb_h.timeout = 15 * 1000;
534         ccb->ccb_h.cbfcnp = mmcprobe_done;
535 }
536
537 static void
538 mmcprobe_start(struct cam_periph *periph, union ccb *start_ccb)
539 {
540         mmcprobe_softc *softc;
541         struct cam_path *path;
542         struct ccb_mmcio *mmcio;
543         struct mtx *p_mtx = cam_periph_mtx(periph);
544         struct ccb_trans_settings_mmc *cts;
545
546         CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_PROBE, ("mmcprobe_start\n"));
547         softc = (mmcprobe_softc *)periph->softc;
548         path = start_ccb->ccb_h.path;
549         mmcio = &start_ccb->mmcio;
550         cts = &start_ccb->cts.proto_specific.mmc;
551         struct mmc_params *mmcp = &path->device->mmc_ident_data;
552
553         memset(&mmcio->cmd, 0, sizeof(struct mmc_command));
554
555         if (softc->restart) {
556                 softc->restart = 0;
557                 if (path->device->flags & CAM_DEV_UNCONFIGURED)
558                         softc->action = PROBE_RESET;
559                 else
560                         softc->action = PROBE_IDENTIFY;
561
562         }
563
564         /* Here is the place where the identify fun begins */
565         switch (softc->action) {
566         case PROBE_RESET:
567                 /* FALLTHROUGH */
568         case PROBE_IDENTIFY:
569                 xpt_path_inq(&start_ccb->cpi, periph->path);
570
571                 CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_PROBE, ("Start with PROBE_RESET\n"));
572                 init_standard_ccb(start_ccb, XPT_SET_TRAN_SETTINGS);
573                 cts->ios.power_mode = power_off;
574                 cts->ios_valid = MMC_PM;
575                 xpt_action(start_ccb);
576                 mtx_sleep(periph, p_mtx, 0, "mmcios", 100);
577
578                 /* mmc_power_up */
579                 /* Get the host OCR */
580                 init_standard_ccb(start_ccb, XPT_GET_TRAN_SETTINGS);
581                 xpt_action(start_ccb);
582
583                 uint32_t hv = mmc_highest_voltage(cts->host_ocr);
584                 init_standard_ccb(start_ccb, XPT_SET_TRAN_SETTINGS);
585                 cts->ios.vdd = hv;
586                 cts->ios.bus_mode = opendrain;
587                 cts->ios.chip_select = cs_dontcare;
588                 cts->ios.power_mode = power_up;
589                 cts->ios.bus_width = bus_width_1;
590                 cts->ios.clock = 0;
591                 cts->ios_valid = MMC_VDD | MMC_PM | MMC_BM |
592                         MMC_CS | MMC_BW | MMC_CLK;
593                 xpt_action(start_ccb);
594                 mtx_sleep(periph, p_mtx, 0, "mmcios", 100);
595
596                 init_standard_ccb(start_ccb, XPT_SET_TRAN_SETTINGS);
597                 cts->ios.power_mode = power_on;
598                 cts->ios.clock = CARD_ID_FREQUENCY;
599                 cts->ios.timing = bus_timing_normal;
600                 cts->ios_valid = MMC_PM | MMC_CLK | MMC_BT;
601                 xpt_action(start_ccb);
602                 mtx_sleep(periph, p_mtx, 0, "mmcios", 100);
603                 /* End for mmc_power_on */
604
605                 /* Begin mmc_idle_cards() */
606                 init_standard_ccb(start_ccb, XPT_SET_TRAN_SETTINGS);
607                 cts->ios.chip_select = cs_high;
608                 cts->ios_valid = MMC_CS;
609                 xpt_action(start_ccb);
610                 mtx_sleep(periph, p_mtx, 0, "mmcios", 1);
611
612                 CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_PROBE, ("Send first XPT_MMC_IO\n"));
613                 init_standard_ccb(start_ccb, XPT_MMC_IO);
614                 mmcio->cmd.opcode = MMC_GO_IDLE_STATE; /* CMD 0 */
615                 mmcio->cmd.arg = 0;
616                 mmcio->cmd.flags = MMC_RSP_NONE | MMC_CMD_BC;
617                 mmcio->cmd.data = NULL;
618                 mmcio->stop.opcode = 0;
619
620                 /* XXX Reset I/O portion as well */
621                 break;
622         case PROBE_SDIO_RESET:
623                 CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_PROBE,
624                           ("Start with PROBE_SDIO_RESET\n"));
625                 uint32_t mmc_arg = SD_IO_RW_ADR(SD_IO_CCCR_CTL)
626                         | SD_IO_RW_DAT(CCCR_CTL_RES) | SD_IO_RW_WR | SD_IO_RW_RAW;
627                 cam_fill_mmcio(&start_ccb->mmcio,
628                                /*retries*/ 0,
629                                /*cbfcnp*/ mmcprobe_done,
630                                /*flags*/ CAM_DIR_NONE,
631                                /*mmc_opcode*/ SD_IO_RW_DIRECT,
632                                /*mmc_arg*/ mmc_arg,
633                                /*mmc_flags*/ MMC_RSP_R5 | MMC_CMD_AC,
634                                /*mmc_data*/ NULL,
635                                /*timeout*/ 1000);
636                 break;
637         case PROBE_SEND_IF_COND:
638                 CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_PROBE,
639                           ("Start with PROBE_SEND_IF_COND\n"));
640                 init_standard_ccb(start_ccb, XPT_MMC_IO);
641                 mmcio->cmd.opcode = SD_SEND_IF_COND; /* CMD 8 */
642                 mmcio->cmd.arg = (1 << 8) + 0xAA;
643                 mmcio->cmd.flags = MMC_RSP_R7 | MMC_CMD_BCR;
644                 mmcio->stop.opcode = 0;
645                 break;
646
647         case PROBE_SDIO_INIT:
648                 CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_PROBE,
649                           ("Start with PROBE_SDIO_INIT\n"));
650                 init_standard_ccb(start_ccb, XPT_MMC_IO);
651                 mmcio->cmd.opcode = IO_SEND_OP_COND; /* CMD 5 */
652                 mmcio->cmd.arg = mmcp->io_ocr;
653                 mmcio->cmd.flags = MMC_RSP_R4;
654                 mmcio->stop.opcode = 0;
655                 break;
656
657         case PROBE_MMC_INIT:
658                 CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_PROBE,
659                           ("Start with PROBE_MMC_INIT\n"));
660                 init_standard_ccb(start_ccb, XPT_MMC_IO);
661                 mmcio->cmd.opcode = MMC_SEND_OP_COND; /* CMD 1 */
662                 mmcio->cmd.arg = MMC_OCR_CCS | mmcp->card_ocr; /* CCS + ocr */;
663                 mmcio->cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR;
664                 mmcio->stop.opcode = 0;
665                 break;
666
667         case PROBE_SEND_APP_OP_COND:
668                 init_standard_ccb(start_ccb, XPT_MMC_IO);
669                 if (softc->flags & PROBE_FLAG_ACMD_SENT) {
670                         mmcio->cmd.opcode = ACMD_SD_SEND_OP_COND; /* CMD 41 */
671                         /*
672                          * We set CCS bit because we do support SDHC cards.
673                          * XXX: Don't set CCS if no response to CMD8.
674                          */
675                         uint32_t cmd_arg = MMC_OCR_CCS | mmcp->card_ocr; /* CCS + ocr */
676                         if (softc->acmd41_count < 10 && mmcp->card_ocr != 0 )
677                                 cmd_arg |= MMC_OCR_S18R;
678                         mmcio->cmd.arg = cmd_arg;
679                         mmcio->cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR;
680                         softc->acmd41_count++;
681                 } else {
682                         mmcio->cmd.opcode = MMC_APP_CMD; /* CMD 55 */
683                         mmcio->cmd.arg = 0; /* rca << 16 */
684                         mmcio->cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
685                 }
686                 mmcio->stop.opcode = 0;
687                 break;
688
689         case PROBE_GET_CID: /* XXX move to mmc_da */
690                 init_standard_ccb(start_ccb, XPT_MMC_IO);
691                 mmcio->cmd.opcode = MMC_ALL_SEND_CID;
692                 mmcio->cmd.arg = 0;
693                 mmcio->cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR;
694                 mmcio->stop.opcode = 0;
695                 break;
696
697         case PROBE_SEND_RELATIVE_ADDR:
698                 init_standard_ccb(start_ccb, XPT_MMC_IO);
699                 mmcio->cmd.opcode = SD_SEND_RELATIVE_ADDR;
700                 mmcio->cmd.arg = 0;
701                 mmcio->cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR;
702                 mmcio->stop.opcode = 0;
703                 break;
704         case PROBE_SELECT_CARD:
705                 init_standard_ccb(start_ccb, XPT_MMC_IO);
706                 mmcio->cmd.opcode = MMC_SELECT_CARD;
707                 mmcio->cmd.arg = (uint32_t)path->device->mmc_ident_data.card_rca << 16;
708                 mmcio->cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
709                 mmcio->stop.opcode = 0;
710                 break;
711         case PROBE_GET_CSD: /* XXX move to mmc_da */
712                 init_standard_ccb(start_ccb, XPT_MMC_IO);
713                 mmcio->cmd.opcode = MMC_SEND_CSD;
714                 mmcio->cmd.arg = (uint32_t)path->device->mmc_ident_data.card_rca << 16;
715                 mmcio->cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR;
716                 mmcio->stop.opcode = 0;
717                 break;
718         case PROBE_DONE:
719                 CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_PROBE, ("Start with PROBE_DONE\n"));
720                 init_standard_ccb(start_ccb, XPT_SET_TRAN_SETTINGS);
721                 cts->ios.bus_mode = pushpull;
722                 cts->ios_valid = MMC_BM;
723                 xpt_action(start_ccb);
724                 return;
725                 /* NOTREACHED */
726                 break;
727         case PROBE_INVALID:
728                 break;
729         default:
730                 CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_PROBE, ("probestart: invalid action state 0x%x\n", softc->action));
731                 panic("default: case in mmc_probe_start()");
732         }
733
734         start_ccb->ccb_h.flags |= CAM_DEV_QFREEZE;
735         xpt_action(start_ccb);
736 }
737
738 static void mmcprobe_cleanup(struct cam_periph *periph)
739 {
740         free(periph->softc, M_CAMXPT);
741 }
742
743 static void
744 mmcprobe_done(struct cam_periph *periph, union ccb *done_ccb)
745 {
746         mmcprobe_softc *softc;
747         struct cam_path *path;
748
749         int err;
750         struct ccb_mmcio *mmcio;
751         u_int32_t  priority;
752
753         CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE, ("mmcprobe_done\n"));
754         softc = (mmcprobe_softc *)periph->softc;
755         path = done_ccb->ccb_h.path;
756         priority = done_ccb->ccb_h.pinfo.priority;
757
758         switch (softc->action) {
759         case PROBE_RESET:
760                 /* FALLTHROUGH */
761         case PROBE_IDENTIFY:
762         {
763                 printf("Starting completion of PROBE_RESET\n");
764                 CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE, ("done with PROBE_RESET\n"));
765                 mmcio = &done_ccb->mmcio;
766                 err = mmcio->cmd.error;
767
768                 if (err != MMC_ERR_NONE) {
769                         CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
770                                   ("GO_IDLE_STATE failed with error %d\n",
771                                    err));
772
773                         /* There was a device there, but now it's gone... */
774                         if ((path->device->flags & CAM_DEV_UNCONFIGURED) == 0) {
775                                 xpt_async(AC_LOST_DEVICE, path, NULL);
776                         }
777                         PROBE_SET_ACTION(softc, PROBE_INVALID);
778                         break;
779                 }
780                 path->device->protocol = PROTO_MMCSD;
781                 PROBE_SET_ACTION(softc, PROBE_SEND_IF_COND);
782                 break;
783         }
784         case PROBE_SEND_IF_COND:
785         {
786                 mmcio = &done_ccb->mmcio;
787                 err = mmcio->cmd.error;
788                 struct mmc_params *mmcp = &path->device->mmc_ident_data;
789
790                 if (err != MMC_ERR_NONE || mmcio->cmd.resp[0] != 0x1AA) {
791                         CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
792                                   ("IF_COND: error %d, pattern %08x\n",
793                                    err, mmcio->cmd.resp[0]));
794                 } else {
795                         mmcp->card_features |= CARD_FEATURE_SD20;
796                         CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
797                                   ("SD 2.0 interface conditions: OK\n"));
798
799                 }
800                 PROBE_SET_ACTION(softc, PROBE_SDIO_RESET);
801                 break;
802         }
803         case PROBE_SDIO_RESET:
804         {
805                 mmcio = &done_ccb->mmcio;
806                 err = mmcio->cmd.error;
807
808                 CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
809                           ("SDIO_RESET: error %d, CCCR CTL register: %08x\n",
810                            err, mmcio->cmd.resp[0]));
811                 PROBE_SET_ACTION(softc, PROBE_SDIO_INIT);
812                 break;
813         }
814         case PROBE_SDIO_INIT:
815         {
816                 mmcio = &done_ccb->mmcio;
817                 err = mmcio->cmd.error;
818                 struct mmc_params *mmcp = &path->device->mmc_ident_data;
819
820                 CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
821                           ("SDIO_INIT: error %d, %08x %08x %08x %08x\n",
822                            err, mmcio->cmd.resp[0],
823                            mmcio->cmd.resp[1],
824                            mmcio->cmd.resp[2],
825                            mmcio->cmd.resp[3]));
826
827                 /*
828                  * Error here means that this card is not SDIO,
829                  * so proceed with memory init as if nothing has happened
830                  */
831                 if (err != MMC_ERR_NONE) {
832                         PROBE_SET_ACTION(softc, PROBE_SEND_APP_OP_COND);
833                         break;
834                 }
835                 mmcp->card_features |= CARD_FEATURE_SDIO;
836                 uint32_t ioifcond = mmcio->cmd.resp[0];
837                 uint32_t io_ocr = ioifcond & R4_IO_OCR_MASK;
838
839                 mmcp->sdio_func_count = R4_IO_NUM_FUNCTIONS(ioifcond);
840                 CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
841                           ("SDIO card: %d functions\n", mmcp->sdio_func_count));
842                 if (io_ocr == 0) {
843                     CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
844                               ("SDIO OCR invalid?!\n"));
845                     break; /* Retry */
846                 }
847
848                 if (io_ocr != 0 && mmcp->io_ocr == 0) {
849                         mmcp->io_ocr = io_ocr;
850                         break; /* Retry, this time with non-0 OCR */
851                 }
852                 CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
853                           ("SDIO OCR: %08x\n", mmcp->io_ocr));
854
855                 if (ioifcond & R4_IO_MEM_PRESENT) {
856                         /* Combo card -- proceed to memory initialization */
857                         PROBE_SET_ACTION(softc, PROBE_SEND_APP_OP_COND);
858                 } else {
859                         /* No memory portion -- get RCA and select card */
860                         PROBE_SET_ACTION(softc, PROBE_SEND_RELATIVE_ADDR);
861                 }
862                 break;
863         }
864         case PROBE_MMC_INIT:
865         {
866                 mmcio = &done_ccb->mmcio;
867                 err = mmcio->cmd.error;
868                 struct mmc_params *mmcp = &path->device->mmc_ident_data;
869
870                 if (err != MMC_ERR_NONE) {
871                         CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
872                                   ("MMC_INIT: error %d, resp %08x\n",
873                                    err, mmcio->cmd.resp[0]));
874                         PROBE_SET_ACTION(softc, PROBE_INVALID);
875                         break;
876                 }
877                 CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
878                           ("MMC card, OCR %08x\n", mmcio->cmd.resp[0]));
879
880                 if (mmcp->card_ocr == 0) {
881                         /* We haven't sent the OCR to the card yet -- do it */
882                         mmcp->card_ocr = mmcio->cmd.resp[0];
883                         CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
884                                   ("-> sending OCR to card\n"));
885                         break;
886                 }
887
888                 if (!(mmcio->cmd.resp[0] & MMC_OCR_CARD_BUSY)) {
889                         CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
890                                   ("Card is still powering up\n"));
891                         break;
892                 }
893
894                 mmcp->card_features |= CARD_FEATURE_MMC | CARD_FEATURE_MEMORY;
895                 PROBE_SET_ACTION(softc, PROBE_GET_CID);
896                 break;
897         }
898         case PROBE_SEND_APP_OP_COND:
899         {
900                 mmcio = &done_ccb->mmcio;
901                 err = mmcio->cmd.error;
902
903                 if (err != MMC_ERR_NONE) {
904                         CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
905                                   ("APP_OP_COND: error %d, resp %08x\n",
906                                    err, mmcio->cmd.resp[0]));
907                         PROBE_SET_ACTION(softc, PROBE_MMC_INIT);
908                         break;
909                 }
910
911                 if (!(softc->flags & PROBE_FLAG_ACMD_SENT)) {
912                         /* Don't change the state */
913                         softc->flags |= PROBE_FLAG_ACMD_SENT;
914                         break;
915                 }
916
917                 softc->flags &= ~PROBE_FLAG_ACMD_SENT;
918                 if ((mmcio->cmd.resp[0] & MMC_OCR_CARD_BUSY) ||
919                     (mmcio->cmd.arg & MMC_OCR_VOLTAGE) == 0) {
920                         struct mmc_params *mmcp = &path->device->mmc_ident_data;
921                         CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
922                                   ("Card OCR: %08x\n",  mmcio->cmd.resp[0]));
923                         if (mmcp->card_ocr == 0) {
924                                 mmcp->card_ocr = mmcio->cmd.resp[0];
925                                 /* Now when we know OCR that we want -- send it to card */
926                                 CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
927                                           ("-> sending OCR to card\n"));
928                         } else {
929                                 /* We already know the OCR and despite of that we
930                                  * are processing the answer to ACMD41 -> move on
931                                  */
932                                 PROBE_SET_ACTION(softc, PROBE_GET_CID);
933                         }
934                         /* Getting an answer to ACMD41 means the card has memory */
935                         mmcp->card_features |= CARD_FEATURE_MEMORY;
936
937                         /* Standard capacity vs High Capacity memory card */
938                         if (mmcio->cmd.resp[0] & MMC_OCR_CCS) {
939                                 CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
940                                           ("Card is SDHC\n"));
941                                 mmcp->card_features |= CARD_FEATURE_SDHC;
942                         }
943
944                         /* Whether the card supports 1.8V signaling */
945                         if (mmcio->cmd.resp[0] & MMC_OCR_S18A) {
946                                 CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
947                                           ("Card supports 1.8V signaling\n"));
948                                 mmcp->card_features |= CARD_FEATURE_18V;
949                         }
950                 } else {
951                         CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
952                                   ("Card not ready: %08x\n",  mmcio->cmd.resp[0]));
953                         /* Send CMD55+ACMD41 once again  */
954                         PROBE_SET_ACTION(softc, PROBE_SEND_APP_OP_COND);
955                 }
956
957                 break;
958         }
959         case PROBE_GET_CID: /* XXX move to mmc_da */
960         {
961                 mmcio = &done_ccb->mmcio;
962                 err = mmcio->cmd.error;
963
964                 if (err != MMC_ERR_NONE) {
965                         CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
966                                   ("PROBE_GET_CID: error %d\n", err));
967                         PROBE_SET_ACTION(softc, PROBE_INVALID);
968                         break;
969                 }
970
971                 struct mmc_params *mmcp = &path->device->mmc_ident_data;
972                 memcpy(mmcp->card_cid, mmcio->cmd.resp, 4 * sizeof(uint32_t));
973                 CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
974                           ("CID %08x%08x%08x%08x\n",
975                            mmcp->card_cid[0],
976                            mmcp->card_cid[1],
977                            mmcp->card_cid[2],
978                            mmcp->card_cid[3]));
979                 PROBE_SET_ACTION(softc, PROBE_SEND_RELATIVE_ADDR);
980                 break;
981         }
982         case PROBE_SEND_RELATIVE_ADDR: {
983                 mmcio = &done_ccb->mmcio;
984                 err = mmcio->cmd.error;
985                 struct mmc_params *mmcp = &path->device->mmc_ident_data;
986                 uint16_t rca = mmcio->cmd.resp[0] >> 16;
987                 CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
988                           ("Card published RCA: %u\n", rca));
989                 path->device->mmc_ident_data.card_rca = rca;
990                 if (err != MMC_ERR_NONE) {
991                         CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
992                                   ("PROBE_SEND_RELATIVE_ADDR: error %d\n", err));
993                         PROBE_SET_ACTION(softc, PROBE_INVALID);
994                         break;
995                 }
996
997                 /* If memory is present, get CSD, otherwise select card */
998                 if (mmcp->card_features & CARD_FEATURE_MEMORY)
999                         PROBE_SET_ACTION(softc, PROBE_GET_CSD);
1000                 else
1001                         PROBE_SET_ACTION(softc, PROBE_SELECT_CARD);
1002                 break;
1003         }
1004         case PROBE_GET_CSD: {
1005                 mmcio = &done_ccb->mmcio;
1006                 err = mmcio->cmd.error;
1007
1008                 if (err != MMC_ERR_NONE) {
1009                         CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
1010                                   ("PROBE_GET_CSD: error %d\n", err));
1011                         PROBE_SET_ACTION(softc, PROBE_INVALID);
1012                         break;
1013                 }
1014
1015                 struct mmc_params *mmcp = &path->device->mmc_ident_data;
1016                 memcpy(mmcp->card_csd, mmcio->cmd.resp, 4 * sizeof(uint32_t));
1017                 CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
1018                           ("CSD %08x%08x%08x%08x\n",
1019                            mmcp->card_csd[0],
1020                            mmcp->card_csd[1],
1021                            mmcp->card_csd[2],
1022                            mmcp->card_csd[3]));
1023                 PROBE_SET_ACTION(softc, PROBE_SELECT_CARD);
1024                 break;
1025         }
1026         case PROBE_SELECT_CARD: {
1027                 mmcio = &done_ccb->mmcio;
1028                 err = mmcio->cmd.error;
1029                 if (err != MMC_ERR_NONE) {
1030                         CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
1031                                   ("PROBE_SEND_RELATIVE_ADDR: error %d\n", err));
1032                         PROBE_SET_ACTION(softc, PROBE_INVALID);
1033                         break;
1034                 }
1035
1036                 PROBE_SET_ACTION(softc, PROBE_DONE);
1037                 break;
1038         }
1039         default:
1040                 CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
1041                           ("mmc_probedone: invalid action state 0x%x\n", softc->action));
1042                 panic("default: case in mmc_probe_done()");
1043         }
1044
1045         if (softc->action == PROBE_INVALID &&
1046             (path->device->flags & CAM_DEV_UNCONFIGURED) == 0) {
1047                 CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE,
1048                           ("mmc_probedone: Should send AC_LOST_DEVICE but won't for now\n"));
1049                 //xpt_async(AC_LOST_DEVICE, path, NULL);
1050         }
1051
1052         xpt_release_ccb(done_ccb);
1053         if (softc->action != PROBE_INVALID)
1054                 xpt_schedule(periph, priority);
1055         /* Drop freeze taken due to CAM_DEV_QFREEZE flag set. */
1056         int frozen = cam_release_devq(path, 0, 0, 0, FALSE);
1057         printf("mmc_probedone: remaining freezecnt %d\n", frozen);
1058
1059         if (softc->action == PROBE_DONE) {
1060                 /* Notify the system that the device is found! */
1061                 if (periph->path->device->flags & CAM_DEV_UNCONFIGURED) {
1062                         path->device->flags &= ~CAM_DEV_UNCONFIGURED;
1063                         xpt_acquire_device(path->device);
1064                         done_ccb->ccb_h.func_code = XPT_GDEV_TYPE;
1065                         xpt_action(done_ccb);
1066                         xpt_async(AC_FOUND_DEVICE, path, done_ccb);
1067                 }
1068         }
1069         if (softc->action == PROBE_DONE || softc->action == PROBE_INVALID) {
1070                 cam_periph_invalidate(periph);
1071                 cam_periph_release_locked(periph);
1072         }
1073 }