| /* |
| * Copyright (C) 2016 Google, Inc |
| * Written by Simon Glass <sjg@chromium.org> |
| * |
| * SPDX-License-Identifier: GPL-2.0+ |
| */ |
| |
| #include <common.h> |
| #include <linux/err.h> |
| |
| struct blk_driver *blk_driver_lookup_type(int if_type) |
| { |
| struct blk_driver *drv = ll_entry_start(struct blk_driver, blk_driver); |
| const int n_ents = ll_entry_count(struct blk_driver, blk_driver); |
| struct blk_driver *entry; |
| |
| for (entry = drv; entry != drv + n_ents; entry++) { |
| if (if_type == entry->if_type) |
| return entry; |
| } |
| |
| /* Not found */ |
| return NULL; |
| } |
| |
| static struct blk_driver *blk_driver_lookup_typename(const char *if_typename) |
| { |
| struct blk_driver *drv = ll_entry_start(struct blk_driver, blk_driver); |
| const int n_ents = ll_entry_count(struct blk_driver, blk_driver); |
| struct blk_driver *entry; |
| |
| for (entry = drv; entry != drv + n_ents; entry++) { |
| if (!strcmp(if_typename, entry->if_typename)) |
| return entry; |
| } |
| |
| /* Not found */ |
| return NULL; |
| } |
| |
| const char *blk_get_if_type_name(enum if_type if_type) |
| { |
| struct blk_driver *drv = blk_driver_lookup_type(if_type); |
| |
| return drv ? drv->if_typename : NULL; |
| } |
| |
| /** |
| * get_desc() - Get the block device descriptor for the given device number |
| * |
| * @drv: Legacy block driver |
| * @devnum: Device number (0 = first) |
| * @descp: Returns block device descriptor on success |
| * @return 0 on success, -ENODEV if there is no such device, -ENOSYS if the |
| * driver does not provide a way to find a device, or other -ve on other |
| * error. |
| */ |
| static int get_desc(struct blk_driver *drv, int devnum, struct blk_desc **descp) |
| { |
| if (drv->desc) { |
| if (devnum < 0 || devnum >= drv->max_devs) |
| return -ENODEV; |
| *descp = &drv->desc[devnum]; |
| return 0; |
| } |
| if (!drv->get_dev) |
| return -ENOSYS; |
| |
| return drv->get_dev(devnum, descp); |
| } |
| |
| #ifdef HAVE_BLOCK_DEVICE |
| int blk_list_part(enum if_type if_type) |
| { |
| struct blk_driver *drv; |
| struct blk_desc *desc; |
| int devnum, ok; |
| bool first = true; |
| |
| drv = blk_driver_lookup_type(if_type); |
| if (!drv) |
| return -ENOSYS; |
| for (ok = 0, devnum = 0; devnum < drv->max_devs; ++devnum) { |
| if (get_desc(drv, devnum, &desc)) |
| continue; |
| if (desc->part_type != PART_TYPE_UNKNOWN) { |
| ++ok; |
| if (!first) |
| putc('\n'); |
| part_print(desc); |
| first = false; |
| } |
| } |
| if (!ok) |
| return -ENODEV; |
| |
| return 0; |
| } |
| |
| int blk_print_part_devnum(enum if_type if_type, int devnum) |
| { |
| struct blk_driver *drv = blk_driver_lookup_type(if_type); |
| struct blk_desc *desc; |
| int ret; |
| |
| if (!drv) |
| return -ENOSYS; |
| ret = get_desc(drv, devnum, &desc); |
| if (ret) |
| return ret; |
| if (desc->type == DEV_TYPE_UNKNOWN) |
| return -ENOENT; |
| part_print(desc); |
| |
| return 0; |
| } |
| |
| void blk_list_devices(enum if_type if_type) |
| { |
| struct blk_driver *drv = blk_driver_lookup_type(if_type); |
| struct blk_desc *desc; |
| int i; |
| |
| if (!drv) |
| return; |
| for (i = 0; i < drv->max_devs; ++i) { |
| if (get_desc(drv, i, &desc)) |
| continue; |
| if (desc->type == DEV_TYPE_UNKNOWN) |
| continue; /* list only known devices */ |
| printf("Device %d: ", i); |
| dev_print(desc); |
| } |
| } |
| |
| int blk_print_device_num(enum if_type if_type, int devnum) |
| { |
| struct blk_driver *drv = blk_driver_lookup_type(if_type); |
| struct blk_desc *desc; |
| int ret; |
| |
| if (!drv) |
| return -ENOSYS; |
| ret = get_desc(drv, devnum, &desc); |
| if (ret) |
| return ret; |
| printf("\n%s device %d: ", drv->if_typename, devnum); |
| dev_print(desc); |
| |
| return 0; |
| } |
| |
| int blk_show_device(enum if_type if_type, int devnum) |
| { |
| struct blk_driver *drv = blk_driver_lookup_type(if_type); |
| struct blk_desc *desc; |
| int ret; |
| |
| if (!drv) |
| return -ENOSYS; |
| printf("\nDevice %d: ", devnum); |
| if (devnum >= drv->max_devs) { |
| puts("unknown device\n"); |
| return -ENODEV; |
| } |
| ret = get_desc(drv, devnum, &desc); |
| if (ret) |
| return ret; |
| dev_print(desc); |
| |
| if (desc->type == DEV_TYPE_UNKNOWN) |
| return -ENOENT; |
| |
| return 0; |
| } |
| #endif /* HAVE_BLOCK_DEVICE */ |
| |
| struct blk_desc *blk_get_devnum_by_type(enum if_type if_type, int devnum) |
| { |
| struct blk_driver *drv = blk_driver_lookup_type(if_type); |
| struct blk_desc *desc; |
| |
| if (!drv) |
| return NULL; |
| |
| if (get_desc(drv, devnum, &desc)) |
| return NULL; |
| |
| return desc; |
| } |
| |
| int blk_dselect_hwpart(struct blk_desc *desc, int hwpart) |
| { |
| struct blk_driver *drv = blk_driver_lookup_type(desc->if_type); |
| |
| if (!drv) |
| return -ENOSYS; |
| if (drv->select_hwpart) |
| return drv->select_hwpart(desc, hwpart); |
| |
| return 0; |
| } |
| |
| struct blk_desc *blk_get_devnum_by_typename(const char *if_typename, int devnum) |
| { |
| struct blk_driver *drv = blk_driver_lookup_typename(if_typename); |
| struct blk_desc *desc; |
| |
| if (!drv) |
| return NULL; |
| |
| if (get_desc(drv, devnum, &desc)) |
| return NULL; |
| |
| return desc; |
| } |
| |
| ulong blk_read_devnum(enum if_type if_type, int devnum, lbaint_t start, |
| lbaint_t blkcnt, void *buffer) |
| { |
| struct blk_driver *drv = blk_driver_lookup_type(if_type); |
| struct blk_desc *desc; |
| ulong n; |
| int ret; |
| |
| if (!drv) |
| return -ENOSYS; |
| ret = get_desc(drv, devnum, &desc); |
| if (ret) |
| return ret; |
| n = desc->block_read(desc, start, blkcnt, buffer); |
| if (IS_ERR_VALUE(n)) |
| return n; |
| |
| /* flush cache after read */ |
| flush_cache((ulong)buffer, blkcnt * desc->blksz); |
| |
| return n; |
| } |
| |
| ulong blk_write_devnum(enum if_type if_type, int devnum, lbaint_t start, |
| lbaint_t blkcnt, const void *buffer) |
| { |
| struct blk_driver *drv = blk_driver_lookup_type(if_type); |
| struct blk_desc *desc; |
| int ret; |
| |
| if (!drv) |
| return -ENOSYS; |
| ret = get_desc(drv, devnum, &desc); |
| if (ret) |
| return ret; |
| return desc->block_write(desc, start, blkcnt, buffer); |
| } |
| |
| int blk_select_hwpart_devnum(enum if_type if_type, int devnum, int hwpart) |
| { |
| struct blk_driver *drv = blk_driver_lookup_type(if_type); |
| struct blk_desc *desc; |
| int ret; |
| |
| if (!drv) |
| return -ENOSYS; |
| ret = get_desc(drv, devnum, &desc); |
| if (ret) |
| return ret; |
| return drv->select_hwpart(desc, hwpart); |
| } |