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; 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_init * 184 ***************************************************************************/ 185 int devman_init(void) 186 { 187 int res; 188 189 /* get the endpoint of the HCD */ 190 res = ds_retrieve_label_endpt("devman", &devman_ep); 191 192 if (res != 0) { 193 panic("usb_init: ds_retrieve_label_endpt failed for 'devman': %d", res); 194 } 195 196 TAILQ_INIT(&dev_list); 197 198 return res; 199 } 200 201 /**************************************************************************** 202 * do_bind * 203 ***************************************************************************/ 204 static void do_bind(message *m) 205 { 206 struct devman_dev *dev; 207 int res; 208 209 /* find device */ 210 TAILQ_FOREACH(dev, &dev_list, dev_list) { 211 if (dev->dev_id == m->DEVMAN_DEVICE_ID) { 212 if (dev->bind_cb) { 213 res = dev->bind_cb(dev->data, m->DEVMAN_ENDPOINT); 214 m->m_type = DEVMAN_REPLY; 215 m->DEVMAN_RESULT = res; 216 ipc_send(devman_ep, m); 217 return; 218 } 219 } 220 } 221 m->m_type = DEVMAN_REPLY; 222 m->DEVMAN_RESULT = ENODEV; 223 ipc_send(devman_ep, m); 224 return; 225 } 226 227 /**************************************************************************** 228 * do_unbind * 229 ***************************************************************************/ 230 static void do_unbind(message *m) 231 { 232 struct devman_dev *dev; 233 int res; 234 235 /* find device */ 236 TAILQ_FOREACH(dev, &dev_list, dev_list) { 237 if (dev->dev_id == m->DEVMAN_DEVICE_ID) { 238 if (dev->unbind_cb) { 239 res = dev->unbind_cb(dev->data, m->DEVMAN_ENDPOINT); 240 m->m_type = DEVMAN_REPLY; 241 m->DEVMAN_RESULT = res; 242 ipc_send(devman_ep, m); 243 return; 244 } 245 } 246 } 247 m->m_type = DEVMAN_REPLY; 248 m->DEVMAN_RESULT = ENODEV; 249 ipc_send(devman_ep, m); 250 } 251 252 /**************************************************************************** 253 * devman_handle_msg * 254 ***************************************************************************/ 255 int devman_handle_msg(message *m) 256 { 257 /* make sure msg comes from devman server */ 258 if (m->m_source != devman_ep) { 259 /* we don't honor requests from others by answering them */ 260 return 0; 261 } 262 switch (m->m_type) { 263 case DEVMAN_BIND: 264 do_bind(m); 265 return 1; 266 case DEVMAN_UNBIND: 267 do_unbind(m); 268 return 1; 269 default: 270 return 0; 271 } 272 } 273