Restructure usbms as a preparation for hotplug
This commit is contained in:
parent
4f034dd24d
commit
440ab68551
3 changed files with 227 additions and 169 deletions
|
@ -21,6 +21,7 @@
|
||||||
#include <grub/mm.h>
|
#include <grub/mm.h>
|
||||||
#include <grub/usb.h>
|
#include <grub/usb.h>
|
||||||
#include <grub/misc.h>
|
#include <grub/misc.h>
|
||||||
|
#include <grub/list.h>
|
||||||
|
|
||||||
static grub_usb_controller_dev_t grub_usb_list;
|
static grub_usb_controller_dev_t grub_usb_list;
|
||||||
|
|
||||||
|
@ -232,3 +233,53 @@ grub_usb_device_initialize (grub_usb_device_t dev)
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct grub_usb_attach_desc *attach_hooks;
|
||||||
|
|
||||||
|
void
|
||||||
|
grub_usb_register_attach_hook_class (struct grub_usb_attach_desc *desc)
|
||||||
|
{
|
||||||
|
auto int usb_iterate (grub_usb_device_t dev);
|
||||||
|
|
||||||
|
int usb_iterate (grub_usb_device_t usbdev)
|
||||||
|
{
|
||||||
|
struct grub_usb_desc_device *descdev = &usbdev->descdev;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (descdev->class != 0 || descdev->subclass || descdev->protocol != 0
|
||||||
|
|| descdev->configcnt == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* XXX: Just check configuration 0 for now. */
|
||||||
|
for (i = 0; i < usbdev->config[0].descconf->numif; i++)
|
||||||
|
{
|
||||||
|
struct grub_usb_desc_if *interf;
|
||||||
|
|
||||||
|
interf = usbdev->config[0].interf[i].descif;
|
||||||
|
|
||||||
|
grub_dprintf ("usb", "iterate: interf=%d, class=%d, subclass=%d, protocol=%d\n",
|
||||||
|
i, interf->class, interf->subclass, interf->protocol);
|
||||||
|
|
||||||
|
if (usbdev->config[0].interf[i].attached)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (interf->class != desc->class)
|
||||||
|
continue;
|
||||||
|
if (desc->hook (usbdev, 0, i))
|
||||||
|
usbdev->config[0].interf[i].attached = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
desc->next = attach_hooks;
|
||||||
|
attach_hooks = desc;
|
||||||
|
|
||||||
|
grub_usb_iterate (usb_iterate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
grub_usb_unregister_attach_hook_class (struct grub_usb_attach_desc *desc)
|
||||||
|
{
|
||||||
|
grub_list_remove (GRUB_AS_LIST_P (&attach_hooks), GRUB_AS_LIST (desc));
|
||||||
|
}
|
||||||
|
|
187
disk/usbms.c
187
disk/usbms.c
|
@ -52,20 +52,19 @@ struct grub_usbms_dev
|
||||||
|
|
||||||
int luns;
|
int luns;
|
||||||
|
|
||||||
|
int config;
|
||||||
int interface;
|
int interface;
|
||||||
struct grub_usb_desc_endp *in;
|
struct grub_usb_desc_endp *in;
|
||||||
struct grub_usb_desc_endp *out;
|
struct grub_usb_desc_endp *out;
|
||||||
|
|
||||||
int in_maxsz;
|
int in_maxsz;
|
||||||
int out_maxsz;
|
int out_maxsz;
|
||||||
|
|
||||||
struct grub_usbms_dev *next;
|
|
||||||
};
|
};
|
||||||
typedef struct grub_usbms_dev *grub_usbms_dev_t;
|
typedef struct grub_usbms_dev *grub_usbms_dev_t;
|
||||||
|
|
||||||
static grub_usbms_dev_t grub_usbms_dev_list;
|
/* FIXME: remove limit. */
|
||||||
|
#define MAX_USBMS_DEVICES 128
|
||||||
static int devcnt;
|
static grub_usbms_dev_t grub_usbms_devices[MAX_USBMS_DEVICES];
|
||||||
|
|
||||||
static grub_err_t
|
static grub_err_t
|
||||||
grub_usbms_reset (grub_usb_device_t dev, int interface)
|
grub_usbms_reset (grub_usb_device_t dev, int interface)
|
||||||
|
@ -74,58 +73,53 @@ grub_usbms_reset (grub_usb_device_t dev, int interface)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
grub_usbms_finddevs (void)
|
grub_usbms_detach (grub_usb_device_t usbdev, int config, int interface)
|
||||||
{
|
{
|
||||||
auto int usb_iterate (grub_usb_device_t dev);
|
unsigned i;
|
||||||
|
for (i = 0; i < ARRAY_SIZE (grub_usbms_devices); i++)
|
||||||
int usb_iterate (grub_usb_device_t usbdev)
|
if (grub_usbms_devices[i] && grub_usbms_devices[i]->dev == usbdev
|
||||||
|
&& grub_usbms_devices[i]->interface == interface
|
||||||
|
&& grub_usbms_devices[i]->config == config)
|
||||||
{
|
{
|
||||||
grub_usb_err_t err;
|
grub_free (grub_usbms_devices[i]);
|
||||||
struct grub_usb_desc_device *descdev = &usbdev->descdev;
|
grub_usbms_devices[i] = 0;
|
||||||
int i;
|
}
|
||||||
|
|
||||||
if (descdev->class != 0 || descdev->subclass || descdev->protocol != 0
|
|
||||||
|| descdev->configcnt == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* XXX: Just check configuration 0 for now. */
|
|
||||||
for (i = 0; i < usbdev->config[0].descconf->numif; i++)
|
|
||||||
{
|
|
||||||
struct grub_usbms_dev *usbms;
|
|
||||||
struct grub_usb_desc_if *interf;
|
|
||||||
int j;
|
|
||||||
grub_uint8_t luns = 0;
|
|
||||||
|
|
||||||
grub_dprintf ("usbms", "alive\n");
|
|
||||||
|
|
||||||
interf = usbdev->config[0].interf[i].descif;
|
|
||||||
|
|
||||||
/* If this is not a USB Mass Storage device with a supported
|
|
||||||
protocol, just skip it. */
|
|
||||||
grub_dprintf ("usbms", "iterate: interf=%d, class=%d, subclass=%d, protocol=%d\n",
|
|
||||||
i, interf->class, interf->subclass, interf->protocol);
|
|
||||||
|
|
||||||
if (interf->class != GRUB_USB_CLASS_MASS_STORAGE
|
|
||||||
|| ( interf->subclass != GRUB_USBMS_SUBCLASS_BULK &&
|
|
||||||
/* Experimental support of RBC, MMC-2, UFI, SFF-8070i devices */
|
|
||||||
interf->subclass != GRUB_USBMS_SUBCLASS_RBC &&
|
|
||||||
interf->subclass != GRUB_USBMS_SUBCLASS_MMC2 &&
|
|
||||||
interf->subclass != GRUB_USBMS_SUBCLASS_UFI &&
|
|
||||||
interf->subclass != GRUB_USBMS_SUBCLASS_SFF8070 )
|
|
||||||
|| interf->protocol != GRUB_USBMS_PROTOCOL_BULK)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
grub_dprintf ("usbms", "alive\n");
|
static int
|
||||||
|
grub_usbms_attach (grub_usb_device_t usbdev, int configno, int interfno)
|
||||||
|
{
|
||||||
|
struct grub_usb_desc_if *interf
|
||||||
|
= usbdev->config[configno].interf[interfno].descif;
|
||||||
|
int j;
|
||||||
|
grub_uint8_t luns = 0;
|
||||||
|
unsigned curnum;
|
||||||
|
grub_usb_err_t err;
|
||||||
|
|
||||||
devcnt++;
|
for (curnum = 0; curnum < ARRAY_SIZE (grub_usbms_devices); curnum++)
|
||||||
usbms = grub_zalloc (sizeof (struct grub_usbms_dev));
|
if (!grub_usbms_devices[curnum])
|
||||||
if (! usbms)
|
break;
|
||||||
return 1;
|
|
||||||
|
|
||||||
usbms->dev = usbdev;
|
if (curnum == ARRAY_SIZE (grub_usbms_devices))
|
||||||
usbms->interface = i;
|
return 0;
|
||||||
|
|
||||||
|
interf = usbdev->config[configno].interf[interfno].descif;
|
||||||
|
|
||||||
|
if ((interf->subclass != GRUB_USBMS_SUBCLASS_BULK
|
||||||
|
/* Experimental support of RBC, MMC-2, UFI, SFF-8070i devices */
|
||||||
|
&& interf->subclass != GRUB_USBMS_SUBCLASS_RBC
|
||||||
|
&& interf->subclass != GRUB_USBMS_SUBCLASS_MMC2
|
||||||
|
&& interf->subclass != GRUB_USBMS_SUBCLASS_UFI
|
||||||
|
&& interf->subclass != GRUB_USBMS_SUBCLASS_SFF8070 )
|
||||||
|
|| interf->protocol != GRUB_USBMS_PROTOCOL_BULK)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
grub_usbms_devices[curnum] = grub_zalloc (sizeof (struct grub_usbms_dev));
|
||||||
|
if (! grub_usbms_devices[curnum])
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
grub_usbms_devices[curnum]->dev = usbdev;
|
||||||
|
grub_usbms_devices[curnum]->interface = interfno;
|
||||||
|
|
||||||
grub_dprintf ("usbms", "alive\n");
|
grub_dprintf ("usbms", "alive\n");
|
||||||
|
|
||||||
|
@ -134,29 +128,30 @@ grub_usbms_finddevs (void)
|
||||||
for (j = 0; j < interf->endpointcnt; j++)
|
for (j = 0; j < interf->endpointcnt; j++)
|
||||||
{
|
{
|
||||||
struct grub_usb_desc_endp *endp;
|
struct grub_usb_desc_endp *endp;
|
||||||
endp = &usbdev->config[0].interf[i].descendp[j];
|
endp = &usbdev->config[0].interf[interfno].descendp[j];
|
||||||
|
|
||||||
if ((endp->endp_addr & 128) && (endp->attrib & 3) == 2)
|
if ((endp->endp_addr & 128) && (endp->attrib & 3) == 2)
|
||||||
{
|
{
|
||||||
/* Bulk IN endpoint. */
|
/* Bulk IN endpoint. */
|
||||||
usbms->in = endp;
|
grub_usbms_devices[curnum]->in = endp;
|
||||||
/* Clear Halt is not possible yet! */
|
/* Clear Halt is not possible yet! */
|
||||||
/* grub_usb_clear_halt (usbdev, endp->endp_addr); */
|
/* grub_usb_clear_halt (usbdev, endp->endp_addr); */
|
||||||
usbms->in_maxsz = endp->maxpacket;
|
grub_usbms_devices[curnum]->in_maxsz = endp->maxpacket;
|
||||||
}
|
}
|
||||||
else if (!(endp->endp_addr & 128) && (endp->attrib & 3) == 2)
|
else if (!(endp->endp_addr & 128) && (endp->attrib & 3) == 2)
|
||||||
{
|
{
|
||||||
/* Bulk OUT endpoint. */
|
/* Bulk OUT endpoint. */
|
||||||
usbms->out = endp;
|
grub_usbms_devices[curnum]->out = endp;
|
||||||
/* Clear Halt is not possible yet! */
|
/* Clear Halt is not possible yet! */
|
||||||
/* grub_usb_clear_halt (usbdev, endp->endp_addr); */
|
/* grub_usb_clear_halt (usbdev, endp->endp_addr); */
|
||||||
usbms->out_maxsz = endp->maxpacket;
|
grub_usbms_devices[curnum]->out_maxsz = endp->maxpacket;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!usbms->in || !usbms->out)
|
if (!grub_usbms_devices[curnum]->in || !grub_usbms_devices[curnum]->out)
|
||||||
{
|
{
|
||||||
grub_free (usbms);
|
grub_free (grub_usbms_devices[curnum]);
|
||||||
|
grub_usbms_devices[curnum] = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,32 +161,30 @@ grub_usbms_finddevs (void)
|
||||||
grub_usb_set_configuration (usbdev, 1);
|
grub_usb_set_configuration (usbdev, 1);
|
||||||
|
|
||||||
/* Query the amount of LUNs. */
|
/* Query the amount of LUNs. */
|
||||||
err = grub_usb_control_msg (usbdev, 0xA1, 254,
|
err = grub_usb_control_msg (usbdev, 0xA1, 254, 0, interfno, 1, (char *) &luns);
|
||||||
0, i, 1, (char *) &luns);
|
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
/* In case of a stall, clear the stall. */
|
/* In case of a stall, clear the stall. */
|
||||||
if (err == GRUB_USB_ERR_STALL)
|
if (err == GRUB_USB_ERR_STALL)
|
||||||
{
|
{
|
||||||
grub_usb_clear_halt (usbdev, usbms->in->endp_addr);
|
grub_usb_clear_halt (usbdev, grub_usbms_devices[curnum]->in->endp_addr);
|
||||||
grub_usb_clear_halt (usbdev, usbms->out->endp_addr);
|
grub_usb_clear_halt (usbdev, grub_usbms_devices[curnum]->out->endp_addr);
|
||||||
}
|
}
|
||||||
/* Just set the amount of LUNs to one. */
|
/* Just set the amount of LUNs to one. */
|
||||||
grub_errno = GRUB_ERR_NONE;
|
grub_errno = GRUB_ERR_NONE;
|
||||||
usbms->luns = 1;
|
grub_usbms_devices[curnum]->luns = 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
/* luns = 0 means one LUN with ID 0 present ! */
|
/* luns = 0 means one LUN with ID 0 present ! */
|
||||||
/* We get from device not number of LUNs but highest
|
/* We get from device not number of LUNs but highest
|
||||||
* LUN number. LUNs are numbered from 0,
|
* LUN number. LUNs are numbered from 0,
|
||||||
* i.e. number of LUNs is luns+1 ! */
|
* i.e. number of LUNs is luns+1 ! */
|
||||||
usbms->luns = luns + 1;
|
grub_usbms_devices[curnum]->luns = luns + 1;
|
||||||
|
|
||||||
grub_dprintf ("usbms", "alive\n");
|
grub_dprintf ("usbms", "alive\n");
|
||||||
|
|
||||||
usbms->next = grub_usbms_dev_list;
|
usbdev->config[configno].interf[interfno].detach_hook = grub_usbms_detach;
|
||||||
grub_usbms_dev_list = usbms;
|
|
||||||
|
|
||||||
#if 0 /* All this part should be probably deleted.
|
#if 0 /* All this part should be probably deleted.
|
||||||
* This make trouble on some devices if they are not in
|
* This make trouble on some devices if they are not in
|
||||||
|
@ -206,17 +199,7 @@ grub_usbms_finddevs (void)
|
||||||
grub_usb_clear_halt (usbdev, usbms->out->endp_addr);
|
grub_usb_clear_halt (usbdev, usbms->out->endp_addr);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 1;
|
||||||
}
|
|
||||||
|
|
||||||
grub_dprintf ("usbms", "alive\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
grub_dprintf ("usbms", "alive\n");
|
|
||||||
|
|
||||||
grub_usb_iterate (usb_iterate);
|
|
||||||
grub_dprintf ("usbms", "alive\n");
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -224,21 +207,20 @@ grub_usbms_finddevs (void)
|
||||||
static int
|
static int
|
||||||
grub_usbms_iterate (int (*hook) (const char *name, int luns))
|
grub_usbms_iterate (int (*hook) (const char *name, int luns))
|
||||||
{
|
{
|
||||||
grub_usbms_dev_t p;
|
unsigned i;
|
||||||
int cnt = 0;
|
|
||||||
|
|
||||||
for (p = grub_usbms_dev_list; p; p = p->next)
|
for (i = 0; i < ARRAY_SIZE (grub_usbms_devices); i++)
|
||||||
|
if (grub_usbms_devices[i])
|
||||||
{
|
{
|
||||||
char *devname;
|
char *devname;
|
||||||
devname = grub_xasprintf ("usb%d", cnt);
|
devname = grub_xasprintf ("usb%d", i);
|
||||||
|
|
||||||
if (hook (devname, p->luns))
|
if (hook (devname, grub_usbms_devices[i]->luns))
|
||||||
{
|
{
|
||||||
grub_free (devname);
|
grub_free (devname);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
grub_free (devname);
|
grub_free (devname);
|
||||||
cnt++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -400,36 +382,26 @@ grub_usbms_write (struct grub_scsi *scsi, grub_size_t cmdsize, char *cmd,
|
||||||
static grub_err_t
|
static grub_err_t
|
||||||
grub_usbms_open (const char *name, struct grub_scsi *scsi)
|
grub_usbms_open (const char *name, struct grub_scsi *scsi)
|
||||||
{
|
{
|
||||||
grub_usbms_dev_t p;
|
|
||||||
int devnum;
|
int devnum;
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
if (grub_strncmp (name, "usb", 3))
|
if (grub_strncmp (name, "usb", 3))
|
||||||
return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
|
return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
|
||||||
"not a USB Mass Storage device");
|
"not a USB Mass Storage device");
|
||||||
|
|
||||||
devnum = grub_strtoul (name + 3, NULL, 10);
|
devnum = grub_strtoul (name + 3, NULL, 10);
|
||||||
for (p = grub_usbms_dev_list; p; p = p->next)
|
if (!grub_usbms_devices[devnum])
|
||||||
{
|
return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
|
||||||
/* Check if this is the devnumth device. */
|
"not a USB Mass Storage device");
|
||||||
if (devnum == i)
|
|
||||||
{
|
scsi->data = grub_usbms_devices[devnum];
|
||||||
scsi->data = p;
|
|
||||||
scsi->name = grub_strdup (name);
|
scsi->name = grub_strdup (name);
|
||||||
scsi->luns = p->luns;
|
scsi->luns = grub_usbms_devices[devnum]->luns;
|
||||||
if (! scsi->name)
|
if (! scsi->name)
|
||||||
return grub_errno;
|
return grub_errno;
|
||||||
|
|
||||||
return GRUB_ERR_NONE;
|
return GRUB_ERR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
|
|
||||||
"not a USB Mass Storage device");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
grub_usbms_close (struct grub_scsi *scsi)
|
grub_usbms_close (struct grub_scsi *scsi)
|
||||||
{
|
{
|
||||||
|
@ -446,13 +418,28 @@ static struct grub_scsi_dev grub_usbms_dev =
|
||||||
.write = grub_usbms_write
|
.write = grub_usbms_write
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct grub_usb_attach_desc attach_hook =
|
||||||
|
{
|
||||||
|
.class = GRUB_USB_CLASS_MASS_STORAGE,
|
||||||
|
.hook = grub_usbms_attach
|
||||||
|
};
|
||||||
|
|
||||||
GRUB_MOD_INIT(usbms)
|
GRUB_MOD_INIT(usbms)
|
||||||
{
|
{
|
||||||
grub_usbms_finddevs ();
|
grub_usb_register_attach_hook_class (&attach_hook);
|
||||||
grub_scsi_dev_register (&grub_usbms_dev);
|
grub_scsi_dev_register (&grub_usbms_dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
GRUB_MOD_FINI(usbms)
|
GRUB_MOD_FINI(usbms)
|
||||||
{
|
{
|
||||||
|
unsigned i;
|
||||||
|
for (i = 0; i < ARRAY_SIZE (grub_usbms_devices); i++)
|
||||||
|
{
|
||||||
|
grub_usbms_devices[i]->dev->config[grub_usbms_devices[i]->config]
|
||||||
|
.interf[grub_usbms_devices[i]->interface].detach_hook = 0;
|
||||||
|
grub_usbms_devices[i]->dev->config[grub_usbms_devices[i]->config]
|
||||||
|
.interf[grub_usbms_devices[i]->interface].attached = 0;
|
||||||
|
}
|
||||||
|
grub_usb_unregister_attach_hook_class (&attach_hook);
|
||||||
grub_scsi_dev_unregister (&grub_usbms_dev);
|
grub_scsi_dev_unregister (&grub_usbms_dev);
|
||||||
}
|
}
|
||||||
|
|
|
@ -125,6 +125,13 @@ struct grub_usb_interface
|
||||||
struct grub_usb_desc_if *descif;
|
struct grub_usb_desc_if *descif;
|
||||||
|
|
||||||
struct grub_usb_desc_endp *descendp;
|
struct grub_usb_desc_endp *descendp;
|
||||||
|
|
||||||
|
/* A driver is handling this interface. Do we need to support multiple drivers
|
||||||
|
for single interface?
|
||||||
|
*/
|
||||||
|
int attached;
|
||||||
|
|
||||||
|
void (*detach_hook) (struct grub_usb_device *dev, int config, int interface);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct grub_usb_configuration
|
struct grub_usb_configuration
|
||||||
|
@ -207,4 +214,17 @@ grub_usb_get_config_interface (struct grub_usb_desc_config *config)
|
||||||
return interf;
|
return interf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef int (*grub_usb_attach_hook_class) (grub_usb_device_t usbdev,
|
||||||
|
int configno, int interfno);
|
||||||
|
|
||||||
|
struct grub_usb_attach_desc
|
||||||
|
{
|
||||||
|
struct grub_usb_attach_desc *next;
|
||||||
|
int class;
|
||||||
|
grub_usb_attach_hook_class hook;
|
||||||
|
};
|
||||||
|
|
||||||
|
void grub_usb_register_attach_hook_class (struct grub_usb_attach_desc *desc);
|
||||||
|
void grub_usb_unregister_attach_hook_class (struct grub_usb_attach_desc *desc);
|
||||||
|
|
||||||
#endif /* GRUB_USB_H */
|
#endif /* GRUB_USB_H */
|
||||||
|
|
Loading…
Reference in a new issue