int kvss905c_set_windows(int fd, const struct kvss905c_window *window, char duplex, u8 *requestsense) { // see page 35 u8 windowbytes[6 + 2 + WINDOW_SIZE]; memset(windowbytes, 0, sizeof(windowbytes)); const int bytes_written = kvss905c_window_serialise(windowbytes + 8, window); if (bytes_written != WINDOW_SIZE) abort(); const u16 length = htons(WINDOW_SIZE); memcpy(windowbytes + 6, &length, sizeof(length)); static const int transfer_length = sizeof(windowbytes); const u8 command[] = {0x24, 0, 0, 0, 0, 0, transfer_length >> 16, transfer_length >> 8, transfer_length, 0}; const int r = scsi_command(fd, SG_DXFER_TO_DEV, command, sizeof(command), windowbytes, transfer_length, requestsense, 0); if (r) return r; if (duplex) { windowbytes[8] = 0x80; return scsi_command(fd, SG_DXFER_TO_DEV, command, sizeof(command), windowbytes, transfer_length, requestsense, 0); } return 0; }
/* * sd_read_capacity: * * Find out from the device what its capacity is. */ static uint64_t sd_read_capacity(struct sd_softc *sd, int *blksize) { union { struct scsipi_read_capacity_10 cmd; struct scsipi_read_capacity_16 cmd16; } cmd; union { struct scsipi_read_capacity_10_data data; struct scsipi_read_capacity_16_data data16; } data; uint64_t rv; memset(&cmd, 0, sizeof(cmd)); cmd.cmd.opcode = READ_CAPACITY_10; /* * If the command works, interpret the result as a 4 byte * number of blocks */ rv = 0; memset(&data, 0, sizeof(data.data)); if (scsi_command(sd, (void *)&cmd.cmd, sizeof(cmd.cmd), (void *)&data, sizeof(data.data)) != 0) goto out; if (_4btol(data.data.addr) != 0xffffffff) { *blksize = _4btol(data.data.length); rv = _4btol(data.data.addr) + 1; goto out; } /* * Device is larger than can be reflected by READ CAPACITY (10). * Try READ CAPACITY (16). */ memset(&cmd, 0, sizeof(cmd)); cmd.cmd16.opcode = READ_CAPACITY_16; cmd.cmd16.byte2 = SRC16_SERVICE_ACTION; _lto4b(sizeof(data.data16), cmd.cmd16.len); memset(&data, 0, sizeof(data.data16)); if (scsi_command(sd, (void *)&cmd.cmd16, sizeof(cmd.cmd16), (void *)&data, sizeof(data.data16)) != 0) goto out; *blksize = _4btol(data.data16.length); rv = _8btol(data.data16.addr) + 1; out: return rv; }
int kvss905c_stop(int fd, u8 *requestsense) { // see page 89 static const u8 command[] = {0xe1, 0, 0x8b, 0, 0, 0, 0, 0, 0, 0}; return scsi_command(fd, SG_DXFER_TO_DEV, command, sizeof(command), NULL, 0, requestsense, 0); }
int kvss905c_read(int fd, u8 type, u8 q1, u8 q2, u8 *buffer, u32 length, u8 *requestsense) { // see page 50 const u8 command[] = {0x28, 0, type, 0, q1, q2, length >> 16, length >> 8, length, 0}; return scsi_command(fd, SG_DXFER_FROM_DEV, command, sizeof(command), buffer, length, requestsense, 0); }
int scsi_mode_sense(struct sd_softc *sd, int byte2, int page, struct scsi_mode_parameter_header_6 *data, int len) { struct scsi_mode_sense_6 cmd; memset(&cmd, 0, sizeof(cmd)); cmd.opcode = SCSI_MODE_SENSE_6; cmd.byte2 = byte2; cmd.page = page; cmd.length = len & 0xff; return scsi_command(sd, (void *)&cmd, sizeof(cmd), (void *)data, len); }
int kvss905c_detect(int fd) { // see page 28 u8 requestsense[REQUEST_SENSE_SIZE]; u8 inquirydata[96]; memset(inquirydata, 0, sizeof(inquirydata)); static const u8 command[] = {0x12, 0, 0, 0, 0x60, 0}; const int r = scsi_command(fd, SG_DXFER_FROM_DEV, command, sizeof(command), inquirydata, sizeof(inquirydata), requestsense, 0); if (r) return r; // We check that the model string begins with "KV-" return memcmp(inquirydata + 16, "KV-", 3); }
int get_data_buffer_status(int fd, u8 *window_id, u32 *length, u8 *requestsense) { // see page 71 u8 buffer[12]; static const u8 command[] = {0x34, 0, 0, 0, 0, 0, 0, 0, sizeof(buffer), 0}; const int r = scsi_command(fd, SG_DXFER_FROM_DEV, command, sizeof(command), buffer, sizeof(buffer), requestsense, 0); if (r) return r; *window_id = buffer[4]; const u32 length_be = ((u32) buffer[9]) << 16 | ((u32) buffer[10]) << 8 | ((u32) buffer[11]); *length = ntohl(length_be); return 0; }
int test_unit_ready(int fd, u8 *requestsense) { static const u8 command[] = {0, 0, 0, 0, 0, 0}; return scsi_command(fd, SG_DXFER_FROM_DEV, command, sizeof(command), NULL, 0, requestsense, 0); }
void nscsi_full_device::step(bool timeout) { UINT32 ctrl = scsi_bus->ctrl_r(); UINT32 data = scsi_bus->data_r(); if(ctrl & S_RST) { scsi_bus->data_w(scsi_refid, 0); scsi_bus->ctrl_w(scsi_refid, 0, S_ALL); scsi_state = IDLE; logerror("%s: scsi bus reset\n", tag()); return; } if(0) logerror("%s: state=%d.%d %s\n", tag(), scsi_state & STATE_MASK, (scsi_state & SUB_MASK) >> SUB_SHIFT, timeout ? "timeout" : "change"); switch(scsi_state & SUB_MASK ? scsi_state & SUB_MASK : scsi_state & STATE_MASK) { case IDLE: if(((ctrl & (S_SEL|S_BSY)) == S_SEL) && (scsi_id != -1) && ((data & (1 << scsi_id)) != 0)) { for(scsi_initiator_id = 0; scsi_initiator_id != 16 && (scsi_initiator_id == scsi_id || (data & (1 << scsi_initiator_id))); scsi_initiator_id++); if(scsi_initiator_id == 16) scsi_initiator_id = -1; scsi_state = TARGET_SELECT_WAIT_BUS_SETTLE; scsi_timer->adjust(scsi_bus_settle_delay()); } break; case TARGET_SELECT_WAIT_BUS_SETTLE: if((ctrl & (S_SEL|S_BSY)) == S_SEL) { scsi_state = TARGET_SELECT_WAIT_SEL_0; scsi_bus->ctrl_w(scsi_refid, S_BSY, S_BSY); } else scsi_state = IDLE; break; case TARGET_SELECT_WAIT_SEL_0: if(ctrl & S_SEL) break; buf_control_push()->action = BC_MSG_OR_COMMAND; scsi_state = TARGET_NEXT_CONTROL; step(false); break; case RECV_BYTE_T_WAIT_ACK_1 << SUB_SHIFT: if(ctrl & S_ACK) { scsi_put_data(data_buffer_id, data_buffer_pos++, scsi_bus->data_r()); scsi_state = (scsi_state & STATE_MASK) | (RECV_BYTE_T_WAIT_ACK_0 << SUB_SHIFT); scsi_bus->ctrl_w(scsi_refid, 0, S_REQ); } break; case RECV_BYTE_T_WAIT_ACK_0 << SUB_SHIFT: if(!(ctrl & S_ACK)) { scsi_state &= STATE_MASK; scsi_bus->ctrl_wait(scsi_refid, 0, S_ACK); step(false); } break; case SEND_BYTE_T_WAIT_ACK_1 << SUB_SHIFT: if(ctrl & S_ACK) { scsi_state = (scsi_state & STATE_MASK) | (SEND_BYTE_T_WAIT_ACK_0 << SUB_SHIFT); scsi_bus->data_w(scsi_refid, 0); scsi_bus->ctrl_w(scsi_refid, 0, S_REQ); } break; case SEND_BYTE_T_WAIT_ACK_0 << SUB_SHIFT: if(!(ctrl & S_ACK)) { scsi_state &= STATE_MASK; scsi_bus->ctrl_wait(scsi_refid, 0, S_ACK); step(false); } break; case TARGET_NEXT_CONTROL: { control *ctl = buf_control_pop(); switch(ctl->action) { case BC_MSG_OR_COMMAND: data_buffer_id = SBUF_MAIN; data_buffer_pos = 0; if(ctrl & S_ATN) { scsi_state = TARGET_WAIT_MSG_BYTE; scsi_bus->ctrl_w(scsi_refid, S_PHASE_MSG_OUT, S_PHASE_MASK); } else { scsi_state = TARGET_WAIT_CMD_BYTE; scsi_bus->ctrl_w(scsi_refid, S_PHASE_COMMAND, S_PHASE_MASK); } target_recv_byte(); break; case BC_STATUS: scsi_bus->ctrl_w(scsi_refid, S_PHASE_STATUS, S_PHASE_MASK); target_send_byte(ctl->param1); break; case BC_DATA_IN: scsi_bus->ctrl_w(scsi_refid, S_PHASE_DATA_IN, S_PHASE_MASK); data_buffer_id = ctl->param1; data_buffer_size = ctl->param2; data_buffer_pos = 0; scsi_state = TARGET_WAIT_DATA_IN_BYTE; target_send_buffer_byte(); break; case BC_DATA_OUT: scsi_bus->ctrl_w(scsi_refid, S_PHASE_DATA_OUT, S_PHASE_MASK); data_buffer_id = ctl->param1; data_buffer_size = ctl->param2; data_buffer_pos = 0; scsi_state = TARGET_WAIT_DATA_OUT_BYTE; target_recv_byte(); break; case BC_MESSAGE_1: scsi_bus->ctrl_w(scsi_refid, S_PHASE_MSG_IN, S_PHASE_MASK); target_send_byte(ctl->param1); break; case BC_BUS_FREE: scsi_bus->data_w(scsi_refid, 0); scsi_bus->ctrl_wait(scsi_refid, S_BSY|S_SEL|S_RST, S_ALL); scsi_bus->ctrl_w(scsi_refid, 0, S_ALL); scsi_state = IDLE; break; }; break; } case TARGET_WAIT_DATA_IN_BYTE: if(data_buffer_pos == data_buffer_size-1) scsi_state = TARGET_NEXT_CONTROL; target_send_buffer_byte(); break; case TARGET_WAIT_DATA_OUT_BYTE: if(data_buffer_pos == data_buffer_size-1) scsi_state = TARGET_NEXT_CONTROL; target_recv_byte(); break; case TARGET_WAIT_MSG_BYTE: if(ctrl & S_SEL) return; if(!(ctrl & S_ATN)) { scsi_cmdsize = data_buffer_pos; scsi_message(); data_buffer_id = SBUF_MAIN; data_buffer_pos = 0; scsi_state = TARGET_WAIT_CMD_BYTE; scsi_bus->ctrl_w(scsi_refid, S_PHASE_COMMAND, S_PHASE_MASK); } target_recv_byte(); break; case TARGET_WAIT_CMD_BYTE: if(ctrl & S_SEL) return; if(ctrl & S_ATN) { logerror("%s: Parity error? Say what?\n", tag()); scsi_state = IDLE; break; } if(command_done()) { scsi_cmdsize = data_buffer_pos; scsi_bus->ctrl_wait(scsi_refid, 0, S_ACK); scsi_command(); scsi_state = TARGET_NEXT_CONTROL; step(false); } else target_recv_byte(); break; default: logerror("%s: step() unexpected state %d.%d\n", tag(), scsi_state & STATE_MASK, (scsi_state & SUB_MASK) >> SUB_SHIFT); exit(0); } }
// // USB Callbacks // bool CALLBACK_MS_Device_SCSICommandReceived(USB_ClassInfo_MS_Device_t* const device) { return scsi_command(sd, device); }
/* * Read some data. */ int sdstrategy(void *f, int rw, daddr_t dblk, size_t size, void *p, size_t *rsize) { struct sd_softc *sd; struct disklabel *lp; struct partition *pp; struct scsipi_generic *cmdp; struct scsipi_rw_16 cmd16; struct scsipi_rw_10 cmd_big; struct scsi_rw_6 cmd_small; daddr_t blkno; int cmdlen, nsect, i; uint8_t *buf; if (size == 0) return 0; if (rw != F_READ) return EOPNOTSUPP; buf = p; sd = f; lp = &sd->sc_label; pp = &lp->d_partitions[sd->sc_part]; if (!(sd->sc_flags & FLAGS_MEDIA_LOADED)) return EIO; nsect = howmany(size, lp->d_secsize); blkno = dblk + pp->p_offset; for (i = 0; i < nsect; i++, blkno++) { int error; /* * Fill out the scsi command. Use the smallest CDB possible * (6-byte, 10-byte, or 16-byte). */ if ((blkno & 0x1fffff) == blkno) { /* 6-byte CDB */ memset(&cmd_small, 0, sizeof(cmd_small)); cmd_small.opcode = SCSI_READ_6_COMMAND; _lto3b(blkno, cmd_small.addr); cmd_small.length = 1; cmdlen = sizeof(cmd_small); cmdp = (struct scsipi_generic *)&cmd_small; } else if ((blkno & 0xffffffff) == blkno) { /* 10-byte CDB */ memset(&cmd_big, 0, sizeof(cmd_big)); cmd_small.opcode = READ_10; _lto4b(blkno, cmd_big.addr); _lto2b(1, cmd_big.length); cmdlen = sizeof(cmd_big); cmdp = (struct scsipi_generic *)&cmd_big; } else { /* 16-byte CDB */ memset(&cmd16, 0, sizeof(cmd16)); cmd_small.opcode = READ_16; _lto8b(blkno, cmd16.addr); _lto4b(1, cmd16.length); cmdlen = sizeof(cmd16); cmdp = (struct scsipi_generic *)&cmd16; } error = scsi_command(sd, cmdp, cmdlen, buf, lp->d_secsize); if (error) return error; buf += lp->d_secsize; } *rsize = size; return 0; }
/* * Open device (read drive parameters and disklabel) */ int sdopen(struct open_file *f, ...) { struct sd_softc *sd; struct scsi_test_unit_ready cmd; struct scsipi_inquiry_data *inqbuf; u_int bus, target, lun, part; int error; char buf[SCSIPI_INQUIRY_LENGTH_SCSI2]; va_list ap; va_start(ap, f); bus = 0; target = va_arg(ap, u_int); lun = va_arg(ap, u_int); part = va_arg(ap, u_int); va_end(ap); DPRINTF(("sdopen: sd(%d,%d,%d)\n", target, lun, part)); sd = alloc(sizeof(struct sd_softc)); if (sd == NULL) return ENOMEM; memset(sd, 0, sizeof(struct sd_softc)); sd->sc_part = part; sd->sc_lun = lun; sd->sc_target = target; sd->sc_bus = bus; if ((error = scsi_inquire(sd, sizeof(buf), buf)) != 0) return error; inqbuf = (struct scsipi_inquiry_data *)buf; sd->sc_type = inqbuf->device & SID_TYPE; /* * Determine the operating mode capabilities of the device. */ if ((inqbuf->version & SID_ANSII) >= 2) { // if ((inqbuf->flags3 & SID_CmdQue) != 0) // sd->sc_cap |= PERIPH_CAP_TQING; if ((inqbuf->flags3 & SID_Sync) != 0) sd->sc_cap |= PERIPH_CAP_SYNC; /* SPC-2 */ if ((inqbuf->version & SID_ANSII) >= 3) { /* * Report ST clocking though CAP_WIDExx/CAP_SYNC. * If the device only supports DT, clear these * flags (DT implies SYNC and WIDE) */ switch (inqbuf->flags4 & SID_Clocking) { case SID_CLOCKING_DT_ONLY: sd->sc_cap &= ~PERIPH_CAP_SYNC; break; } } } sd->sc_flags = (inqbuf->dev_qual2 & SID_REMOVABLE) ? FLAGS_REMOVABLE : 0; memset(&cmd, 0, sizeof(cmd)); cmd.opcode = SCSI_TEST_UNIT_READY; if ((error = scsi_command(sd, (void *)&cmd, sizeof(cmd), NULL, 0)) != 0) return error; if (sd->sc_flags & FLAGS_REMOVABLE) { printf("XXXXX: removable device found. will not support\n"); } if (!(sd->sc_flags & FLAGS_MEDIA_LOADED)) sd->sc_flags |= FLAGS_MEDIA_LOADED; if ((error = sd_get_parms(sd)) != 0) return error; strncpy(sd->sc_label.d_typename, inqbuf->product, 16); if ((error = sdgetdisklabel(sd)) != 0) return error; f->f_devdata = sd; return 0; }
/* * Get the scsi driver to send a full inquiry to the * device and use the * results to fill out the disk parameter structure. */ static int sd_get_capacity(struct sd_softc *sd) { struct disk_parms *dp = &sd->sc_params; uint64_t blocks; int error, blksize; dp->disksize = blocks = sd_read_capacity(sd, &blksize); if (blocks == 0) { struct scsipi_read_format_capacities cmd; struct { struct scsipi_capacity_list_header header; struct scsipi_capacity_descriptor desc; } __packed data; memset(&cmd, 0, sizeof(cmd)); memset(&data, 0, sizeof(data)); cmd.opcode = READ_FORMAT_CAPACITIES; _lto2b(sizeof(data), cmd.length); error = scsi_command(sd, (void *)&cmd, sizeof(cmd), (void *)&data, sizeof(data)); if (error == EFTYPE) /* Medium Format Corrupted, handle as not formatted */ return SDGP_RESULT_UNFORMATTED; if (error || data.header.length == 0) return SDGP_RESULT_OFFLINE; switch (data.desc.byte5 & SCSIPI_CAP_DESC_CODE_MASK) { case SCSIPI_CAP_DESC_CODE_RESERVED: case SCSIPI_CAP_DESC_CODE_FORMATTED: break; case SCSIPI_CAP_DESC_CODE_UNFORMATTED: return SDGP_RESULT_UNFORMATTED; case SCSIPI_CAP_DESC_CODE_NONE: return SDGP_RESULT_OFFLINE; } dp->disksize = blocks = _4btol(data.desc.nblks); if (blocks == 0) return SDGP_RESULT_OFFLINE; /* XXX? */ blksize = _3btol(data.desc.blklen); } else if (!sd_validate_blksize(blksize)) { struct sd_mode_sense_data scsipi_sense; int bsize; memset(&scsipi_sense, 0, sizeof(scsipi_sense)); error = scsi_mode_sense(sd, 0, 0, &scsipi_sense.header, sizeof(struct scsi_mode_parameter_header_6) + sizeof(scsipi_sense.blk_desc)); if (!error) { bsize = scsipi_sense.header.blk_desc_len; if (bsize >= 8) blksize = _3btol(scsipi_sense.blk_desc.blklen); } } if (!sd_validate_blksize(blksize)) blksize = SD_DEFAULT_BLKSIZE; dp->blksize = blksize; dp->disksize512 = (blocks * dp->blksize) / DEV_BSIZE; return 0; }
HalDevice * devinfo_mass_add(HalDevice *parent, const char *devnode, char *devfs_path, char *device_type) { HalDevice *d = NULL, *gparent = NULL; prop_dictionary_t dict; struct disklabel label; struct stat st; const char *driver; char *rdevpath, *devpath; char *childnode; char *parent_devnode, *gparent_devnode = NULL; char *gparent_udi; int16_t unit; int i, fd; struct scsipi_inquiry_data inqbuf; struct scsipi_inquiry cmd; bool scsiinq_status; char *storage_model = NULL, *storage_vendor = NULL; if (drvctl_find_device (devnode, &dict) == FALSE || dict == NULL) return NULL; if (prop_dictionary_get_int16 (dict, "device-unit", &unit) == false || prop_dictionary_get_cstring_nocopy (dict, "device-driver", &driver) == false) { prop_object_release (dict); return NULL; } if (strcmp (driver, "wd") != 0 && strcmp (driver, "sd") != 0 && strcmp (driver, "ld") != 0) { prop_object_release (dict); return NULL; } sleep (1); devpath = g_strdup_printf ("/dev/%s%c", devnode, RAW_PART + 'a'); rdevpath = g_strdup_printf ("/dev/r%s%c", devnode, RAW_PART + 'a'); HAL_INFO ((" going to open %s", rdevpath)); fd = open (rdevpath, O_RDONLY); if (fd < 0) { HAL_WARNING (("couldn't open %s: %s", rdevpath, strerror (errno))); g_free (rdevpath); g_free (devpath); return NULL; } HAL_INFO ((" going to DIOCGDINFO %s", rdevpath)); if (ioctl (fd, DIOCGDINFO, &label) == -1) { HAL_WARNING (("DIOCGDINFO failed on %s: %s", rdevpath, strerror (errno))); g_free (rdevpath); g_free (devpath); close (fd); return NULL; } if (strcmp (driver, "sd") == 0) { memset(&cmd, 0, sizeof (cmd)); memset(&inqbuf, 0, sizeof (inqbuf)); cmd.opcode = INQUIRY; cmd.length = sizeof (inqbuf); scsiinq_status = scsi_command (fd, &cmd, sizeof (cmd), &inqbuf, sizeof (inqbuf), 10000, SCCMD_READ); } else scsiinq_status = false; close (fd); d = hal_device_new (); devinfo_set_default_properties (d, parent, devnode, devfs_path); hal_device_add_capability (d, "block"); hal_device_property_set_string (d, "info.subsystem", "block"); hal_device_property_set_string (d, "block.device", devpath); if (stat (devpath, &st) == 0) { hal_device_property_set_int (d, "block.major", major (st.st_rdev)); hal_device_property_set_int (d, "block.minor", minor (st.st_rdev)); } hal_device_property_set_bool (d, "block.is_volume", FALSE); hal_device_property_set_bool (d, "block.no_partitions", FALSE); hal_device_property_set_bool (d, "block.have_scanned", TRUE); hal_device_add_capability (d, "storage"); hal_device_property_set_string (d, "info.category", "storage"); parent_devnode = hal_device_property_get_string (parent, "netbsd.device"); gparent_udi = hal_device_property_get_string (parent, "info.parent"); if (gparent_udi) { gparent = hal_device_store_find (hald_get_gdl (), gparent_udi); if (gparent) gparent_devnode = hal_device_property_get_string (gparent, "netbsd.device"); } if (gparent_devnode && strstr (gparent_devnode, "umass") == gparent_devnode) hal_device_property_set_string (d, "storage.bus", "usb"); else if (parent_devnode && strstr (parent_devnode, "atabus") == parent_devnode) hal_device_property_set_string (d, "storage.bus", "ide"); else hal_device_property_set_string (d, "storage.bus", "scsi"); hal_device_property_set_string (d, "storage.device_type", "disk"); hal_device_property_set_bool (d, "storage.removable", label.d_flags & D_REMOVABLE ? TRUE : FALSE); if (label.d_flags & D_REMOVABLE) { hal_device_property_set_bool (d, "storage.removable.media_available", TRUE); hal_device_property_set_uint64 (d, "storage.removable.media_size", (uint64_t)label.d_secsize * (uint64_t)label.d_secperunit); hal_device_property_set_uint64 (d, "storage.size", 0); hal_device_property_set_bool (d, "storage.hotpluggable", TRUE); hal_device_property_set_bool (d, "storage.automount_enabled_hint", TRUE); } else { hal_device_property_set_bool (d, "storage.removable.media_available", FALSE); hal_device_property_set_uint64 (d, "storage.removable.media_size", 0); hal_device_property_set_uint64 (d, "storage.size", (uint64_t)label.d_secsize * (uint64_t)label.d_secperunit); hal_device_property_set_bool (d, "storage.hotpluggable", FALSE); hal_device_property_set_bool (d, "storage.automount_enabled_hint", FALSE); } hal_device_property_set_bool (d, "storage.no_partitions_hint", FALSE); hal_device_property_set_bool (d, "storage.requires_eject", FALSE); hal_device_property_set_bool (d, "storage.removable.support_async_notification", FALSE); hal_device_property_set_string (d, "storage.partitioning_scheme", "mbr"); hal_device_property_set_string (d, "storage.originating_device", hal_device_property_get_string (d, "info.udi")); if (scsiinq_status == true) { storage_model = rtrim_copy(inqbuf.product, sizeof (inqbuf.product)); storage_vendor = rtrim_copy(inqbuf.vendor, sizeof (inqbuf.vendor)); } if (storage_model) { hal_device_property_set_string (d, "storage.model", storage_model); free (storage_model); } else hal_device_property_set_string (d, "storage.model", label.d_packname); if (storage_vendor) { hal_device_property_set_string (d, "storage.vendor", storage_vendor); free (storage_vendor); } else hal_device_property_set_string (d, "storage.vendor", label.d_typename); devinfo_add_enqueue (d, devfs_path, &devinfo_mass_handler); for (i = 0; i < MAXPARTITIONS; i++) { const char *fstype; fstype = devinfo_mass_get_fstype(label.d_partitions[i].p_fstype); if (fstype == NULL) continue; childnode = g_strdup_printf ("%s%c", devnode, 'a' + i); HAL_INFO ((" adding %s on %s", childnode, rdevpath)); devinfo_mass_disklabel_add (d, childnode, childnode, childnode); g_free (childnode); } HAL_INFO ((" returning")); g_free (rdevpath); g_free (devpath); done: prop_object_release (dict); return d; }