1 #include <errno.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <sys/queue.h> 5 #include <minix/com.h> 6 #include <minix/ipc.h> 7 #include <minix/const.h> 8 #include <minix/devman.h> 9 #include <minix/safecopies.h> 10 #include <minix/sysutil.h> 11 #include <minix/ds.h> 12 13 #include "local.h" 14 15 static endpoint_t devman_ep; 16 17 static int save_string(char *buffer, char *src, size_t *offset); 18 19 static TAILQ_HEAD(devlist_head, devman_dev) dev_list; 20 21 /**************************************************************************** 22 * save_string * 23 ***************************************************************************/ 24 static int save_string(char *buffer, char *src, size_t *offset) 25 { 26 unsigned old_offset = *offset; 27 size_t len = strlen(src) + 1; 28 memcpy(buffer + *offset, src, len); 29 *offset += len; 30 return old_offset; 31 } 32 33 /**************************************************************************** 34 * serialize_dev * 35 ***************************************************************************/ 36 void *serialize_dev(struct devman_dev *dev, size_t *overall_size) 37 { 38 /* determine size of serialized version of dev */ 39 char *buffer; 40 char *string_buffer; 41 size_t string_buffer_offset; 42 size_t count = 0; 43 size_t size = sizeof(struct devman_device_info); 44 size_t strings_size = strlen(dev->name) + 1; 45 struct devman_device_info * serialized_dev; 46 struct devman_device_info_entry *entry; 47 struct devman_static_attribute *attribute; 48 49 TAILQ_FOREACH(attribute, &dev->attrs, list) { 50 strings_size += strlen(attribute->name) + 1; 51 strings_size += strlen(attribute->data) + 1; 52 size += sizeof(struct devman_device_info_entry); 53 count++; 54 } 55 56 buffer = malloc(size + strings_size); 57 58 if (buffer == NULL) { 59 return NULL; 60 } 61 62 string_buffer = buffer; 63 string_buffer_offset = size; /* strings start after 64 devman_device_info and 65 devman_device_info_entries */ 66 67 /* serialize device */ 68 serialized_dev = (struct devman_device_info *) buffer; 69 70 serialized_dev->count = count; 71 serialized_dev->parent_dev_id = dev->parent_dev_id; 72 serialized_dev->name_offset = 73 save_string(string_buffer, dev->name, &string_buffer_offset); 74 #if 0 75 serialized_dev->bus = 76 save_string(string_buffer, dev->bus, &string_buffer_offset); 77 #endif 78 79 /* serialize entries */ 80 entry = 81 (struct devman_device_info_entry *) 82 (buffer + sizeof(struct devman_device_info)); 83 84 TAILQ_FOREACH(attribute, &dev->attrs, list) { 85 entry->type = 0; /* TODO: use macro */ 86 entry->name_offset = 87 save_string(string_buffer, attribute->name, &string_buffer_offset); 88 entry->data_offset = 89 save_string(string_buffer, attribute->data, &string_buffer_offset); 90 entry++; 91 } 92 93 *overall_size = size + strings_size; 94 95 return buffer; 96 97 } 98 99 /**************************************************************************** 100 * devman_add_device * 101 ***************************************************************************/ 102 int devman_add_device(struct devman_dev *dev) 103 { 104 message msg; 105 int res; 106 size_t grant_size; 107 void *buf = serialize_dev(dev, &grant_size); 108 109 cp_grant_id_t gid = 110 cpf_grant_direct(devman_ep,(vir_bytes) buf, 111 grant_size, CPF_READ); 112 113 /* prepare message */ 114 msg.m_type = DEVMAN_ADD_DEV; 115 msg.DEVMAN_GRANT_ID = gid; 116 msg.DEVMAN_GRANT_SIZE = grant_size; 117 118 /* send message */ 119 res = ipc_sendrec(devman_ep, &msg); 120 121 if (res != 0) { 122 panic("devman_add_device: could not talk to devman: %d", res); 123 } 124 125 if (msg.m_type != DEVMAN_REPLY) { 126 panic("devman_add_device: got illegal response from devman: %d", 127 msg.m_type); 128 } 129 130 if (msg.DEVMAN_RESULT != 0) { 131 panic("devman_add_device: could add device: %ld", 132 msg.DEVMAN_RESULT); 133 } 134 135 /* store given dev_id to dev */ 136 dev->dev_id = msg.DEVMAN_DEVICE_ID; 137 138 cpf_revoke(gid); 139 140 free(buf); 141 142 /* put device in list */ 143 TAILQ_INSERT_HEAD(&dev_list, dev, dev_list); 144 145 return 0; 146 } 147 148 /**************************************************************************** 149 * devman_del_device * 150 ***************************************************************************/ 151 int devman_del_device(struct devman_dev *dev) 152 { 153 message msg; 154 int res; 155 156 msg.m_type = DEVMAN_DEL_DEV; 157 msg.DEVMAN_DEVICE_ID = dev->dev_id; 158 159 res = ipc_sendrec(devman_ep, &msg); 160 161 if (res != 0) { 162 panic("devman_del_device: could not talk to devman: %d", res); 163 } 164 165 if (msg.m_type != DEVMAN_REPLY) { 166 panic("devman_del_device: got illegal response from devman: %d", 167 msg.m_type); 168 } 169 170 if (msg.DEVMAN_RESULT != 0) { 171 panic("devman_del_device: could delete device: %ld", 172 msg.DEVMAN_RESULT); 173 } 174 175 /* remove the device from list */ 176 TAILQ_REMOVE(&dev_list, dev, dev_list); 177 178 return 0; 179 180 } 181 182 /**************************************************************************** 183 * devman_get_ep * 184 ***************************************************************************/ 185 endpoint_t devman_get_ep(void) 186 { 187 return devman_ep; 188 } 189 190 /**************************************************************************** 191 * devman_init * 192 ***************************************************************************/ 193 int devman_init(void) 194 { 195 int res; 196 197 /* get the endpoint of the HCD */ 198 res = ds_retrieve_label_endpt("devman", &devman_ep); 199 200 if (res != 0) { 201 panic("usb_init: ds_retrieve_label_endpt failed for 'devman': %d", res); 202 } 203 204 TAILQ_INIT(&dev_list); 205 206 return res; 207 } 208 209 /**************************************************************************** 210 * do_bind * 211 ***************************************************************************/ 212 static void do_bind(message *m) 213 { 214 struct devman_dev *dev; 215 int res; 216 217 /* find device */ 218 TAILQ_FOREACH(dev, &dev_list, dev_list) { 219 if (dev->dev_id == m->DEVMAN_DEVICE_ID) { 220 if (dev->bind_cb) { 221 res = dev->bind_cb(dev->data, m->DEVMAN_ENDPOINT); 222 m->m_type = DEVMAN_REPLY; 223 m->DEVMAN_RESULT = res; 224 ipc_send(devman_ep, m); 225 return; 226 } 227 } 228 } 229 m->m_type = DEVMAN_REPLY; 230 m->DEVMAN_RESULT = ENODEV; 231 ipc_send(devman_ep, m); 232 return; 233 } 234 235 /**************************************************************************** 236 * do_unbind * 237 ***************************************************************************/ 238 static void do_unbind(message *m) 239 { 240 struct devman_dev *dev; 241 int res; 242 243 /* find device */ 244 TAILQ_FOREACH(dev, &dev_list, dev_list) { 245 if (dev->dev_id == m->DEVMAN_DEVICE_ID) { 246 if (dev->unbind_cb) { 247 res = dev->unbind_cb(dev->data, m->DEVMAN_ENDPOINT); 248 m->m_type = DEVMAN_REPLY; 249 m->DEVMAN_RESULT = res; 250 ipc_send(devman_ep, m); 251 return; 252 } 253 } 254 } 255 m->m_type = DEVMAN_REPLY; 256 m->DEVMAN_RESULT = ENODEV; 257 ipc_send(devman_ep, m); 258 } 259 260 /**************************************************************************** 261 * devman_handle_msg * 262 ***************************************************************************/ 263 int devman_handle_msg(message *m) 264 { 265 /* make sure msg comes from devman server */ 266 if (m->m_source != devman_ep) { 267 /* we don't honor requests from others by answering them */ 268 return 0; 269 } 270 switch (m->m_type) { 271 case DEVMAN_BIND: 272 do_bind(m); 273 return 1; 274 case DEVMAN_UNBIND: 275 do_unbind(m); 276 return 1; 277 default: 278 return 0; 279 } 280 } 281