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 static 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 = 0; 107 void *buf = serialize_dev(dev, &grant_size); 108 109 if (buf == NULL) 110 panic("out of memory"); 111 112 cp_grant_id_t gid = 113 cpf_grant_direct(devman_ep,(vir_bytes) buf, 114 grant_size, CPF_READ); 115 116 /* prepare message */ 117 msg.m_type = DEVMAN_ADD_DEV; 118 msg.DEVMAN_GRANT_ID = gid; 119 msg.DEVMAN_GRANT_SIZE = grant_size; 120 121 /* send message */ 122 res = ipc_sendrec(devman_ep, &msg); 123 124 if (res != 0) { 125 panic("devman_add_device: could not talk to devman: %d", res); 126 } 127 128 if (msg.m_type != DEVMAN_REPLY) { 129 panic("devman_add_device: got illegal response from devman: %d", 130 msg.m_type); 131 } 132 133 if (msg.DEVMAN_RESULT != 0) { 134 panic("devman_add_device: could add device: %ld", 135 msg.DEVMAN_RESULT); 136 } 137 138 /* store given dev_id to dev */ 139 dev->dev_id = msg.DEVMAN_DEVICE_ID; 140 141 cpf_revoke(gid); 142 143 free(buf); 144 145 /* put device in list */ 146 TAILQ_INSERT_HEAD(&dev_list, dev, dev_list); 147 148 return 0; 149 } 150 151 /**************************************************************************** 152 * devman_del_device * 153 ***************************************************************************/ 154 int devman_del_device(struct devman_dev *dev) 155 { 156 message msg; 157 int res; 158 159 msg.m_type = DEVMAN_DEL_DEV; 160 msg.DEVMAN_DEVICE_ID = dev->dev_id; 161 162 res = ipc_sendrec(devman_ep, &msg); 163 164 if (res != 0) { 165 panic("devman_del_device: could not talk to devman: %d", res); 166 } 167 168 if (msg.m_type != DEVMAN_REPLY) { 169 panic("devman_del_device: got illegal response from devman: %d", 170 msg.m_type); 171 } 172 173 if (msg.DEVMAN_RESULT != 0) { 174 panic("devman_del_device: could delete device: %ld", 175 msg.DEVMAN_RESULT); 176 } 177 178 /* remove the device from list */ 179 TAILQ_REMOVE(&dev_list, dev, dev_list); 180 181 return 0; 182 183 } 184 185 /**************************************************************************** 186 * devman_init * 187 ***************************************************************************/ 188 int devman_init(void) 189 { 190 int res; 191 192 /* get the endpoint of the HCD */ 193 res = ds_retrieve_label_endpt("devman", &devman_ep); 194 195 if (res != 0) { 196 panic("usb_init: ds_retrieve_label_endpt failed for 'devman': %d", res); 197 } 198 199 TAILQ_INIT(&dev_list); 200 201 return res; 202 } 203 204 /**************************************************************************** 205 * do_bind * 206 ***************************************************************************/ 207 static void do_bind(message *m) 208 { 209 struct devman_dev *dev; 210 int res; 211 212 /* find device */ 213 TAILQ_FOREACH(dev, &dev_list, dev_list) { 214 if (dev->dev_id == m->DEVMAN_DEVICE_ID) { 215 if (dev->bind_cb) { 216 res = dev->bind_cb(dev->data, m->DEVMAN_ENDPOINT); 217 m->m_type = DEVMAN_REPLY; 218 m->DEVMAN_RESULT = res; 219 ipc_send(devman_ep, m); 220 return; 221 } 222 } 223 } 224 m->m_type = DEVMAN_REPLY; 225 m->DEVMAN_RESULT = ENODEV; 226 ipc_send(devman_ep, m); 227 return; 228 } 229 230 /**************************************************************************** 231 * do_unbind * 232 ***************************************************************************/ 233 static void do_unbind(message *m) 234 { 235 struct devman_dev *dev; 236 int res; 237 238 /* find device */ 239 TAILQ_FOREACH(dev, &dev_list, dev_list) { 240 if (dev->dev_id == m->DEVMAN_DEVICE_ID) { 241 if (dev->unbind_cb) { 242 res = dev->unbind_cb(dev->data, m->DEVMAN_ENDPOINT); 243 m->m_type = DEVMAN_REPLY; 244 m->DEVMAN_RESULT = res; 245 ipc_send(devman_ep, m); 246 return; 247 } 248 } 249 } 250 m->m_type = DEVMAN_REPLY; 251 m->DEVMAN_RESULT = ENODEV; 252 ipc_send(devman_ep, m); 253 } 254 255 /**************************************************************************** 256 * devman_handle_msg * 257 ***************************************************************************/ 258 int devman_handle_msg(message *m) 259 { 260 /* make sure msg comes from devman server */ 261 if (m->m_source != devman_ep) { 262 /* we don't honor requests from others by answering them */ 263 return 0; 264 } 265 switch (m->m_type) { 266 case DEVMAN_BIND: 267 do_bind(m); 268 return 1; 269 case DEVMAN_UNBIND: 270 do_unbind(m); 271 return 1; 272 default: 273 return 0; 274 } 275 } 276