1 /* 2 * Copyright (C) 2016 Google, Inc 3 * Written by Simon Glass <sjg@chromium.org> 4 * 5 * SPDX-License-Identifier: GPL-2.0+ 6 */ 7 8 #include <common.h> 9 #include <blk.h> 10 #include <dm.h> 11 #include <dm/device-internal.h> 12 #include <dm/lists.h> 13 14 int blk_first_device(int if_type, struct udevice **devp) 15 { 16 struct blk_desc *desc; 17 int ret; 18 19 ret = uclass_first_device(UCLASS_BLK, devp); 20 if (ret) 21 return ret; 22 if (!*devp) 23 return -ENODEV; 24 do { 25 desc = dev_get_uclass_platdata(*devp); 26 if (desc->if_type == if_type) 27 return 0; 28 ret = uclass_next_device(devp); 29 if (ret) 30 return ret; 31 } while (*devp); 32 33 return -ENODEV; 34 } 35 36 int blk_next_device(struct udevice **devp) 37 { 38 struct blk_desc *desc; 39 int ret, if_type; 40 41 desc = dev_get_uclass_platdata(*devp); 42 if_type = desc->if_type; 43 do { 44 ret = uclass_next_device(devp); 45 if (ret) 46 return ret; 47 if (!*devp) 48 return -ENODEV; 49 desc = dev_get_uclass_platdata(*devp); 50 if (desc->if_type == if_type) 51 return 0; 52 } while (1); 53 } 54 55 int blk_get_device(int if_type, int devnum, struct udevice **devp) 56 { 57 struct uclass *uc; 58 struct udevice *dev; 59 int ret; 60 61 ret = uclass_get(UCLASS_BLK, &uc); 62 if (ret) 63 return ret; 64 uclass_foreach_dev(dev, uc) { 65 struct blk_desc *desc = dev_get_uclass_platdata(dev); 66 67 debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__, 68 if_type, devnum, dev->name, desc->if_type, desc->devnum); 69 if (desc->if_type == if_type && desc->devnum == devnum) { 70 *devp = dev; 71 return device_probe(dev); 72 } 73 } 74 75 return -ENODEV; 76 } 77 78 unsigned long blk_dread(struct blk_desc *block_dev, lbaint_t start, 79 lbaint_t blkcnt, void *buffer) 80 { 81 struct udevice *dev = block_dev->bdev; 82 const struct blk_ops *ops = blk_get_ops(dev); 83 84 if (!ops->read) 85 return -ENOSYS; 86 87 return ops->read(dev, start, blkcnt, buffer); 88 } 89 90 unsigned long blk_dwrite(struct blk_desc *block_dev, lbaint_t start, 91 lbaint_t blkcnt, const void *buffer) 92 { 93 struct udevice *dev = block_dev->bdev; 94 const struct blk_ops *ops = blk_get_ops(dev); 95 96 if (!ops->write) 97 return -ENOSYS; 98 99 return ops->write(dev, start, blkcnt, buffer); 100 } 101 102 unsigned long blk_derase(struct blk_desc *block_dev, lbaint_t start, 103 lbaint_t blkcnt) 104 { 105 struct udevice *dev = block_dev->bdev; 106 const struct blk_ops *ops = blk_get_ops(dev); 107 108 if (!ops->erase) 109 return -ENOSYS; 110 111 return ops->erase(dev, start, blkcnt); 112 } 113 114 int blk_prepare_device(struct udevice *dev) 115 { 116 struct blk_desc *desc = dev_get_uclass_platdata(dev); 117 118 part_init(desc); 119 120 return 0; 121 } 122 123 int blk_create_device(struct udevice *parent, const char *drv_name, 124 const char *name, int if_type, int devnum, int blksz, 125 lbaint_t size, struct udevice **devp) 126 { 127 struct blk_desc *desc; 128 struct udevice *dev; 129 int ret; 130 131 ret = device_bind_driver(parent, drv_name, name, &dev); 132 if (ret) 133 return ret; 134 desc = dev_get_uclass_platdata(dev); 135 desc->if_type = if_type; 136 desc->blksz = blksz; 137 desc->lba = size / blksz; 138 desc->part_type = PART_TYPE_UNKNOWN; 139 desc->bdev = dev; 140 desc->devnum = devnum; 141 *devp = dev; 142 143 return 0; 144 } 145 146 int blk_unbind_all(int if_type) 147 { 148 struct uclass *uc; 149 struct udevice *dev, *next; 150 int ret; 151 152 ret = uclass_get(UCLASS_BLK, &uc); 153 if (ret) 154 return ret; 155 uclass_foreach_dev_safe(dev, next, uc) { 156 struct blk_desc *desc = dev_get_uclass_platdata(dev); 157 158 if (desc->if_type == if_type) { 159 ret = device_remove(dev); 160 if (ret) 161 return ret; 162 ret = device_unbind(dev); 163 if (ret) 164 return ret; 165 } 166 } 167 168 return 0; 169 } 170 171 UCLASS_DRIVER(blk) = { 172 .id = UCLASS_BLK, 173 .name = "blk", 174 .per_device_platdata_auto_alloc_size = sizeof(struct blk_desc), 175 }; 176