1/**
2 * \file
3 * \brief MMCHS Driver main routine.
4 */
5/*
6 * Copyright (c) 2013, ETH Zurich.
7 * All rights reserved.
8 *
9 * This file is distributed under the terms in the attached LICENSE file.
10 * If you do not find this file, copies can be found by writing to:
11 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
12 */
13
14#include <stdlib.h>
15#include <stdio.h>
16#include <string.h>
17#include <assert.h>
18
19#include <barrelfish/barrelfish.h>
20#include <barrelfish/nameservice_client.h>
21#include <driverkit/driverkit.h>
22
23#include "mmchs.h"
24
25
26static void cm2_connected(void *st, errval_t err, struct cm2_binding *b) {
27    MMCHS_DEBUG("Connected to cm2 driver\n");
28    assert(err_is_ok(err));
29    struct mmchs_driver_state* dst = (struct mmchs_driver_state*) st;
30    cm2_rpc_client_init(b);
31    dst->cm2_binding = b;
32}
33
34static void twl6030_connected(void *st, errval_t err, struct twl6030_binding *b) {
35    MMCHS_DEBUG("Connected to twl6030 driver\n");
36    assert(err_is_ok(err));
37    struct mmchs_driver_state* dst = (struct mmchs_driver_state*) st;
38    twl6030_rpc_client_init(b);
39    dst->twl6030_binding = b;
40}
41
42
43/**
44 * Driver initialization function. This function is called by the driver domain
45 * (see also 'create_handler' in ddomain_service.c).
46 * Typically through a request from the device manager.
47 *
48 * The init function is supposed to set `dev` to the exported service iref.
49 * The init function may use `bfi->dstate` to store additional state about the device.
50 *
51 * \param[in]   bfi   The instance of this driver.
52 * \param[in]   name  The name of this driver instance.
53 * \param[in]   flags Additional flags (The exact flags supported is device/driver specific).
54 * \param[in]   c     Capabilities (for registers etc.) as provided by the device manager.
55 *                    The exact layout of the `c` is device specific.
56 * \param[out]  dev   The service iref over which the device can be contacted.
57 *
58 * \retval SYS_ERR_OK Device initialized successfully.
59 * \retval LIB_ERR_MALLOC_FAIL Unable to allocate memory for the driver.
60 */
61
62static errval_t init(struct bfdriver_instance *bfi, uint64_t flags, iref_t *dev) {
63    MMCHS_DEBUG("%s:%s:%d: %s\n", __FILE__, __FUNCTION__, __LINE__, bfi->driver->name);
64
65    bfi->dstate = malloc(sizeof(struct mmchs_driver_state));
66    if (bfi->dstate == NULL) {
67        return LIB_ERR_MALLOC_FAIL;
68    }
69    assert(bfi->dstate != NULL);
70    struct mmchs_driver_state* st = (struct mmchs_driver_state*) bfi->dstate;
71    st->caps = bfi->caps;
72
73    // Connect to the cm2 driver
74    iref_t cm2_iref;
75    errval_t err = nameservice_lookup("cm2", &cm2_iref);
76    if (err_is_fail(err)) {
77        USER_PANIC_ERR(err, "finding cm2 service failed.");
78    }
79    err = cm2_bind(cm2_iref, cm2_connected, st, get_default_waitset(), IDC_EXPORT_FLAG_NO_NOTIFY);
80    if (err_is_fail(err)) {
81        USER_PANIC_ERR(err, "call failed.");
82    }
83    while(st->cm2_binding == NULL) {
84        messages_wait_and_handle_next();
85    }
86    assert(st->cm2_binding != NULL);
87
88    // Connect to the twl6030 driver
89    iref_t twl6030_iref;
90    err = nameservice_lookup("twl6030", &twl6030_iref);
91    if (err_is_fail(err)) {
92        USER_PANIC_ERR(err, "finding cm2 service failed.");
93    }
94    err = twl6030_bind(twl6030_iref, twl6030_connected, st, get_default_waitset(), IDC_EXPORT_FLAG_NO_NOTIFY);
95    if (err_is_fail(err)) {
96        USER_PANIC_ERR(err, "call failed.");
97    }
98    while(st->twl6030_binding == NULL) {
99        messages_wait_and_handle_next();
100    }
101    assert(st->twl6030_binding != NULL);
102
103    // 1. Initialize the device:
104    ctrlmod_init(st);
105    err = st->cm2_binding->rpc_tx_vtbl.enable_hsmmc1(st->cm2_binding);
106    assert(err_is_ok(err));
107    sdmmc1_enable_power(st);
108    mmchs_init(st);
109
110    // 2. Export service to talk to the device:
111    // FYI: Making this use THC+thread currently fails somewhere in the THC runtime
112    mmchs_init_service(st, dev);
113
114    return SYS_ERR_OK;
115}
116
117/**
118 * Instructs driver to attach to the device.
119 * This function is only called if the driver has previously detached
120 * from the device (see also detach).
121 *
122 * \note After detachment the driver can not assume anything about the
123 * configuration of the device.
124 *
125 * \param[in]   bfi   The instance of this driver.
126 * \retval SYS_ERR_OK Device initialized successfully.
127 */
128static errval_t attach(struct bfdriver_instance* bfi) {
129    MMCHS_DEBUG("%s:%s:%d: %s\n", __FILE__, __FUNCTION__, __LINE__, bfi->driver->name);
130
131    return SYS_ERR_OK;
132}
133
134/**
135 * Instructs driver to detach from the device.
136 * The driver must yield any control over to the device after this function returns.
137 * The device may be left in any state.
138 *
139 * \param[in]   bfi   The instance of this driver.
140 * \retval SYS_ERR_OK Device initialized successfully.
141 */
142static errval_t detach(struct bfdriver_instance* bfi) {
143    MMCHS_DEBUG("%s:%s:%d: %s\n", __FILE__, __FUNCTION__, __LINE__, bfi->driver->name);
144
145    return SYS_ERR_OK;
146}
147
148/**
149 * Instructs the driver to go in a particular sleep state.
150 * Supported states are platform/device specific.
151 *
152 * \param[in]   bfi   The instance of this driver.
153 * \retval SYS_ERR_OK Device initialized successfully.
154 */
155static errval_t set_sleep_level(struct bfdriver_instance* bfi, uint32_t level) {
156    MMCHS_DEBUG("%s:%s:%d: %s\n", __FILE__, __FUNCTION__, __LINE__, bfi->driver->name);
157
158    struct mmchs_driver_state* uds = bfi->dstate;
159    uds->level = level;
160
161    return SYS_ERR_OK;
162}
163
164/**
165 * Destroys this driver instance. The driver will yield any
166 * control over the device and free any state allocated.
167 *
168 * \param[in]   bfi   The instance of this driver.
169 * \retval SYS_ERR_OK Device initialized successfully.
170 */
171static errval_t destroy(struct bfdriver_instance* bfi) {
172    MMCHS_DEBUG("%s:%s:%d: %s\n", __FILE__, __FUNCTION__, __LINE__, bfi->driver->name);
173    struct mmchs_driver_state* uds = bfi->dstate;
174    free(uds);
175    bfi->dstate = NULL;
176
177    // XXX: Tear-down the service
178    bfi->device = 0x0;
179
180    return SYS_ERR_OK;
181}
182
183static errval_t get_ep(struct bfdriver_instance* bfi, bool lmp, struct capref* ret_cap)
184{
185    USER_PANIC("NIY \n");
186    return SYS_ERR_OK;
187}
188
189/**
190 * Registers the driver module with the system.
191 *
192 * To link this particular module in your driver domain,
193 * add it to the addModules list in the Hakefile.
194 */
195DEFINE_MODULE(mmchs, init, attach, detach, set_sleep_level, destroy, get_ep);
196