/* * nextpnr -- Next Generation Place and Route * * Copyright (C) 2018 Clifford Wolf * Copyright (C) 2018 David Shah * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * */ #ifndef NEXTPNR_H #error Include "arch.h" via "nextpnr.h" only. #endif #include #include NEXTPNR_NAMESPACE_BEGIN /**** Everything in this section must be kept in sync with chipdb.py ****/ template struct RelPtr { int32_t offset; // void set(const T *ptr) { // offset = reinterpret_cast(ptr) - // reinterpret_cast(this); // } const T *get() const { return reinterpret_cast(reinterpret_cast(this) + offset); } const T &operator[](size_t index) const { return get()[index]; } const T &operator*() const { return *(get()); } const T *operator->() const { return get(); } }; NPNR_PACKED_STRUCT(struct BelWirePOD { LocationPOD rel_wire_loc; int32_t wire_index; int32_t port; int32_t type; }); NPNR_PACKED_STRUCT(struct BelInfoPOD { RelPtr name; int32_t type; int32_t z; int32_t num_bel_wires; RelPtr bel_wires; }); NPNR_PACKED_STRUCT(struct BelPortPOD { LocationPOD rel_bel_loc; int32_t bel_index; int32_t port; }); NPNR_PACKED_STRUCT(struct PipInfoPOD { LocationPOD rel_src_loc, rel_dst_loc; int32_t src_idx, dst_idx; int32_t delay; int16_t tile_type; int8_t pip_type; int8_t padding_0; }); NPNR_PACKED_STRUCT(struct PipLocatorPOD { LocationPOD rel_loc; int32_t index; }); NPNR_PACKED_STRUCT(struct WireInfoPOD { RelPtr name; int32_t num_uphill, num_downhill; RelPtr pips_uphill, pips_downhill; int32_t num_bel_pins; RelPtr bel_pins; }); NPNR_PACKED_STRUCT(struct LocationTypePOD { int32_t num_bels, num_wires, num_pips; RelPtr bel_data; RelPtr wire_data; RelPtr pip_data; }); NPNR_PACKED_STRUCT(struct PIOInfoPOD { LocationPOD abs_loc; int32_t bel_index; RelPtr function_name; int16_t bank; int16_t padding; }); NPNR_PACKED_STRUCT(struct PackagePinPOD { RelPtr name; LocationPOD abs_loc; int32_t bel_index; }); NPNR_PACKED_STRUCT(struct PackageInfoPOD { RelPtr name; int32_t num_pins; RelPtr pin_data; }); NPNR_PACKED_STRUCT(struct TileNamePOD { RelPtr name; int16_t type_idx; int16_t padding; }); NPNR_PACKED_STRUCT(struct TileInfoPOD { int32_t num_tiles; RelPtr tile_names; }); enum TapDirection : int8_t { TAP_DIR_LEFT = 0, TAP_DIR_RIGHT = 1 }; enum GlobalQuadrant : int8_t { QUAD_UL = 0, QUAD_UR = 1, QUAD_LL = 2, QUAD_LR = 3, }; NPNR_PACKED_STRUCT(struct GlobalInfoPOD { int16_t tap_col; TapDirection tap_dir; GlobalQuadrant quad; int16_t spine_row; int16_t spine_col; }); NPNR_PACKED_STRUCT(struct ChipInfoPOD { int32_t width, height; int32_t num_tiles; int32_t num_location_types; int32_t num_packages, num_pios; RelPtr locations; RelPtr location_type; RelPtr location_glbinfo; RelPtr> tiletype_names; RelPtr package_info; RelPtr pio_info; RelPtr tile_info; }); #if defined(_MSC_VER) extern const char *chipdb_blob_25k; extern const char *chipdb_blob_45k; extern const char *chipdb_blob_85k; #else extern const char chipdb_blob_25k[]; extern const char chipdb_blob_45k[]; extern const char chipdb_blob_85k[]; #endif /************************ End of chipdb section. ************************/ struct BelIterator { const ChipInfoPOD *chip; int cursor_index; int cursor_tile; BelIterator operator++() { cursor_index++; while (cursor_tile < chip->num_tiles && cursor_index >= chip->locations[chip->location_type[cursor_tile]].num_bels) { cursor_index = 0; cursor_tile++; } return *this; } BelIterator operator++(int) { BelIterator prior(*this); ++(*this); return prior; } bool operator!=(const BelIterator &other) const { return cursor_index != other.cursor_index || cursor_tile != other.cursor_tile; } bool operator==(const BelIterator &other) const { return cursor_index == other.cursor_index && cursor_tile == other.cursor_tile; } BelId operator*() const { BelId ret; ret.location.x = cursor_tile % chip->width; ret.location.y = cursor_tile / chip->width; ret.index = cursor_index; return ret; } }; struct BelRange { BelIterator b, e; BelIterator begin() const { return b; } BelIterator end() const { return e; } }; // ----------------------------------------------------------------------- struct BelPinIterator { const BelPortPOD *ptr = nullptr; Location wire_loc; void operator++() { ptr++; } bool operator!=(const BelPinIterator &other) const { return ptr != other.ptr; } BelPin operator*() const { BelPin ret; ret.bel.index = ptr->bel_index; ret.bel.location = wire_loc + ptr->rel_bel_loc; ret.pin.index = ptr->port; return ret; } }; struct BelPinRange { BelPinIterator b, e; BelPinIterator begin() const { return b; } BelPinIterator end() const { return e; } }; // ----------------------------------------------------------------------- struct WireIterator { const ChipInfoPOD *chip; int cursor_index; int cursor_tile; WireIterator operator++() { cursor_index++; while (cursor_tile < chip->num_tiles && cursor_index >= chip->locations[chip->location_type[cursor_tile]].num_wires) { cursor_index = 0; cursor_tile++; } return *this; } WireIterator operator++(int) { WireIterator prior(*this); ++(*this); return prior; } bool operator!=(const WireIterator &other) const { return cursor_index != other.cursor_index || cursor_tile != other.cursor_tile; } bool operator==(const WireIterator &other) const { return cursor_index == other.cursor_index && cursor_tile == other.cursor_tile; } WireId operator*() const { WireId ret; ret.location.x = cursor_tile % chip->width; ret.location.y = cursor_tile / chip->width; ret.index = cursor_index; return ret; } }; struct WireRange { WireIterator b, e; WireIterator begin() const { return b; } WireIterator end() const { return e; } }; // ----------------------------------------------------------------------- struct AllPipIterator { const ChipInfoPOD *chip; int cursor_index; int cursor_tile; AllPipIterator operator++() { cursor_index++; while (cursor_tile < chip->num_tiles && cursor_index >= chip->locations[chip->location_type[cursor_tile]].num_pips) { cursor_index = 0; cursor_tile++; } return *this; } AllPipIterator operator++(int) { AllPipIterator prior(*this); ++(*this); return prior; } bool operator!=(const AllPipIterator &other) const { return cursor_index != other.cursor_index || cursor_tile != other.cursor_tile; } bool operator==(const AllPipIterator &other) const { return cursor_index == other.cursor_index && cursor_tile == other.cursor_tile; } PipId operator*() const { PipId ret; ret.location.x = cursor_tile % chip->width; ret.location.y = cursor_tile / chip->width; ret.index = cursor_index; return ret; } }; struct AllPipRange { AllPipIterator b, e; AllPipIterator begin() const { return b; } AllPipIterator end() const { return e; } }; // ----------------------------------------------------------------------- struct PipIterator { const PipLocatorPOD *cursor = nullptr; Location wire_loc; void operator++() { cursor++; } bool operator!=(const PipIterator &other) const { return cursor != other.cursor; } PipId operator*() const { PipId ret; ret.index = cursor->index; ret.location = wire_loc + cursor->rel_loc; return ret; } }; struct PipRange { PipIterator b, e; PipIterator begin() const { return b; } PipIterator end() const { return e; } }; struct ArchArgs { enum ArchArgsTypes { NONE, LFE5U_25F, LFE5U_45F, LFE5U_85F, LFE5UM_25F, LFE5UM_45F, LFE5UM_85F, LFE5UM5G_25F, LFE5UM5G_45F, LFE5UM5G_85F, } type = NONE; std::string package; int speed = 6; }; struct Arch : BaseCtx { const ChipInfoPOD *chip_info; const PackageInfoPOD *package_info; mutable std::unordered_map bel_by_name; mutable std::unordered_map wire_by_name; mutable std::unordered_map pip_by_name; std::vector bel_to_cell; std::unordered_map wire_to_net; std::unordered_map pip_to_net; ArchArgs args; Arch(ArchArgs args); std::string getChipName() const; IdString archId() const { return id("ecp5"); } ArchArgs archArgs() const { return args; } IdString archArgsToId(ArchArgs args) const; // ------------------------------------------------- int getGridDimX() const { return chip_info->width; }; int getGridDimY() const { return chip_info->height; }; int getTileBelDimZ(int, int) const { return 4; }; int getTilePipDimZ(int, int) const { return 1; }; // ------------------------------------------------- BelId getBelByName(IdString name) const; template const LocationTypePOD *locInfo(Id &id) const { return &(chip_info->locations[chip_info->location_type[id.location.y * chip_info->width + id.location.x]]); } IdString getBelName(BelId bel) const { NPNR_ASSERT(bel != BelId()); std::stringstream name; name << "X" << bel.location.x << "/Y" << bel.location.y << "/" << locInfo(bel)->bel_data[bel.index].name.get(); return id(name.str()); } uint32_t getBelChecksum(BelId bel) const { return bel.index; } const int max_loc_bels = 20; int getBelFlatIndex(BelId bel) const { return (bel.location.y * chip_info->width + bel.location.x) * max_loc_bels + bel.index; } void bindBel(BelId bel, CellInfo *cell, PlaceStrength strength) { NPNR_ASSERT(bel != BelId()); int idx = getBelFlatIndex(bel); NPNR_ASSERT(bel_to_cell.at(idx) == nullptr); bel_to_cell[idx] = cell; cell->bel = bel; cell->belStrength = strength; refreshUiBel(bel); } void unbindBel(BelId bel) { NPNR_ASSERT(bel != BelId()); int idx = getBelFlatIndex(bel); NPNR_ASSERT(bel_to_cell.at(idx) != nullptr); bel_to_cell[idx]->bel = BelId(); bel_to_cell[idx]->belStrength = STRENGTH_NONE; bel_to_cell[idx] = nullptr; refreshUiBel(bel); } Loc getBelLocation(BelId bel) const { Loc loc; loc.x = bel.location.x; loc.y = bel.location.y; loc.z = locInfo(bel)->bel_data[bel.index].z; return loc; } BelId getBelByLocation(Loc loc) const; BelRange getBelsByTile(int x, int y) const; bool getBelGlobalBuf(BelId bel) const { return getBelType(bel) == id_DCCA; } bool checkBelAvail(BelId bel) const { NPNR_ASSERT(bel != BelId()); return bel_to_cell[getBelFlatIndex(bel)] == nullptr; } CellInfo *getBoundBelCell(BelId bel) const { NPNR_ASSERT(bel != BelId()); return bel_to_cell[getBelFlatIndex(bel)]; } CellInfo *getConflictingBelCell(BelId bel) const { NPNR_ASSERT(bel != BelId()); return bel_to_cell[getBelFlatIndex(bel)]; } BelRange getBels() const { BelRange range; range.b.cursor_tile = 0; range.b.cursor_index = -1; range.b.chip = chip_info; ++range.b; //-1 and then ++ deals with the case of no Bels in the first tile range.e.cursor_tile = chip_info->width * chip_info->height; range.e.cursor_index = 0; range.e.chip = chip_info; return range; } IdString getBelType(BelId bel) const { NPNR_ASSERT(bel != BelId()); IdString id; id.index = locInfo(bel)->bel_data[bel.index].type; return id; } std::vector> getBelAttrs(BelId) const { std::vector> ret; return ret; } WireId getBelPinWire(BelId bel, IdString pin) const; BelPinRange getWireBelPins(WireId wire) const { BelPinRange range; NPNR_ASSERT(wire != WireId()); range.b.ptr = locInfo(wire)->wire_data[wire.index].bel_pins.get(); range.b.wire_loc = wire.location; range.e.ptr = range.b.ptr + locInfo(wire)->wire_data[wire.index].num_bel_pins; range.e.wire_loc = wire.location; return range; } std::vector getBelPins(BelId bel) const; // ------------------------------------------------- WireId getWireByName(IdString name) const; IdString getWireName(WireId wire) const { NPNR_ASSERT(wire != WireId()); std::stringstream name; name << "X" << wire.location.x << "/Y" << wire.location.y << "/" << locInfo(wire)->wire_data[wire.index].name.get(); return id(name.str()); } IdString getWireType(WireId wire) const { return IdString(); } std::vector> getWireAttrs(WireId) const { std::vector> ret; return ret; } uint32_t getWireChecksum(WireId wire) const { return wire.index; } void bindWire(WireId wire, NetInfo *net, PlaceStrength strength) { NPNR_ASSERT(wire != WireId()); NPNR_ASSERT(wire_to_net[wire] == nullptr); wire_to_net[wire] = net; net->wires[wire].pip = PipId(); net->wires[wire].strength = strength; } void unbindWire(WireId wire) { NPNR_ASSERT(wire != WireId()); NPNR_ASSERT(wire_to_net[wire] != nullptr); auto &net_wires = wire_to_net[wire]->wires; auto it = net_wires.find(wire); NPNR_ASSERT(it != net_wires.end()); auto pip = it->second.pip; if (pip != PipId()) { pip_to_net[pip] = nullptr; } net_wires.erase(it); wire_to_net[wire] = nullptr; } bool checkWireAvail(WireId wire) const { NPNR_ASSERT(wire != WireId()); return wire_to_net.find(wire) == wire_to_net.end() || wire_to_net.at(wire) == nullptr; } NetInfo *getBoundWireNet(WireId wire) const { NPNR_ASSERT(wire != WireId()); if (wire_to_net.find(wire) == wire_to_net.end()) return nullptr; else return wire_to_net.at(wire); } WireId getConflictingWireWire(WireId wire) const { return wire; } NetInfo *getConflictingWireNet(WireId wire) const { NPNR_ASSERT(wire != WireId()); if (wire_to_net.find(wire) == wire_to_net.end()) return nullptr; else return wire_to_net.at(wire); } DelayInfo getWireDelay(WireId wire) const { DelayInfo delay; delay.delay = 0; return delay; } WireRange getWires() cons
#!/bin/sh
# Copyright (C) 2009-2013 OpenWrt.org

. /lib/functions/leds.sh
. /lib/ar71xx.sh

get_status_led() {
	case $(ar71xx_board_name) in
	alfa-nx)
		status_led="alfa:green:led_8"
		;;
	all0305)
		status_led="eap7660d:green:ds4"
		;;
	antminer-s1)
		status_led="antminer-s1:green:system"
		;;
	antminer-s3)
		status_led="antminer-s3:green:system"
		;;
	ap132)
		status_led="ap132:green:status"
		;;
	ap136-010|\
	ap136-020)
		status_led="ap136:green:status"
		;;
	ap147-010)
		status_led="ap147:green:status"
		;;
	ap135-020)
		status_led="ap135:green:status"
		;;
	ap81)
		status_led="ap81:green:status"
		;;
	ap83)
		status_led="ap83:green:power"
		;;
	ap96)
		status_led="ap96:green:led2"
		;;
	aw-nr580)
		status_led="aw-nr580:green:ready"
		;;
	bsb)
		status_led="bsb:red:sys"
		;;
	bullet-m | rocket-m | rocket-m-xw | nano-m | nanostation-m | nanostation-m-xw | loco-m-xw)
		status_led="ubnt:green:link4"
		;;
	rocket-m-ti)
		status_led="ubnt:green:link6"
		;;
	bxu2000n-2-a1)
		status_led="bhu:green:status"
		;;
	cap4200ag)
		status_led="senao:green:pwr"
		;;
	cf-e316n-v2)
		status_led="$(ar71xx_board_name):blue:wan"
		;;
	cpe510)
		status_led="tp-link:green:link4"
		;;
	db120)
		status_led="db120:green:status"
		;;
	dgl-5500-a1 |\
	dhp-1565-a1|\
	dir-505-a1 |\
	dir-600-a1 |\
	dir-615-e1 |\
	dir-615-i1 |\
	dir-615-e4)
		status_led="d-link:green:power"
		;;
	dir-615-c1)
		status_led="d-link:green:status"
		;;
	dir-825-b1)
		status_led="d-link:orange:power"
		;;
	dir-825-c1 |\
	dir-835-a1)
		status_led="d-link:amber:power"
		;;
	dlan-pro-500-wp)
		status_led="devolo:green:wlan-2g"
		;;
	dlan-pro-1200-ac)
		status_led="devolo:status:wlan"
		;;
	dragino2)
		status_led="dragino2:red:system"
		;;
	eap300v2)
		status_led="engenius:blue:power"
		;;
	eap7660d)
		status_led="eap7660d:green:ds4"
		;;
	el-mini | \
	el-m150)
		status_led="easylink:green:system"
		;;
	ew-dorin | ew-dorin-router)
		status_led="dorin:green:status"
		;;
	f9k1115v2)
		status_led="belkin:blue:status"
		;;
	gl-inet)
		status_led="gl-connect:green:lan"
		;;
	epg5000)
		status_led="epg5000:amber:power"
		;;
	esr1750)
		status_led="esr1750:amber:power"
		;;
	esr900)
		status_led="engenius:amber:power"
		;;
	hiwifi-hc6361)
		status_led="hiwifi:blue:system"
		;;
	hornet-ub | \
	hornet-ub-x2)
		status_led="alfa:blue:wps"
		;;
	ja76pf | \
	ja76pf2)
		status_led="jjplus:green:led1"
		;;
	ls-sr71)
		status_led="ubnt:green:d22"
		;;
	mc-mac1200r)
		status_led="mercury:green:system"
		;;
	mr12)
		status_led="mr12:green:power"
		;;
	mr16)
		status_led="mr16:green:power"
		;;
	mr600)
		status_led="mr600:orange:power"
		;;
	mr600v2)
		status_led="mr600:blue:power"
		;;
	mr1750)
		status_led="mr1750:blue:power"
		;;
	mr900 | \
	mr900v2)
		status_led="mr900:blue:power"
		;;
	mynet-n600 | \
	mynet-n750)
		status_led="wd:blue:power"
		;;
	mynet-rext)
		status_led="wd:blue:power"
		;;
	mzk-w04nu | \
	mzk-w300nh)
		status_led="planex:green:status"
		;;
	nbg460n_550n_550nh)
		status_led="nbg460n:green:power"
		;;
	nbg6716)
		status_led="zyxel:white:power"
		;;
	om2p | \
	om2pv2 | \
	om2p-hs | \
	om2p-hsv2 | \
	om2p-lc)
		status_led="om2p:blue:power"
		;;
	om5p | \
	om5p-an)
		status_led="om5p:blue:power"
		;;
	onion-omega)
		status_led="onion:amber:system"
		;;
	pb44)
		status_led="pb44:amber:jump1"
		;;
	rb-2011l|\
	rb-2011uas|\
	rb-2011uas-2hnd)
		status_led="rb:green:usr"
		;;
	rb-411 | rb-411u | rb-433 | rb-433u | rb-450 | rb-450g | rb-493)
		status_led="rb4xx:yellow:user"
		;;
	rb-750)
		status_led="rb750:green:act"
		;;
	rb-911g-2hpnd|\
	rb-911g-5hpacd|\
	rb-911g-5hpnd|\
	rb-912uag-2hpnd|\
	rb-912uag-5hpnd)
		status_led="rb:green:user"
		;;
	rb-951ui-2hnd)
		status_led="rb:green:act"
		;;
	rb-sxt2n|\
	rb-sxt5n)
		status_led="rb:green:power"
		;;
	routerstation | routerstation-pro)
		status_led="ubnt:green:rf"
		;;
	rw2458n)
		status_led="rw2458n:green:d3"
		;;
	smart-300)
		status_led="nc-link:green:system"
		;;
	minibox-v1)
		status_led="minibox-v1:green:system"
		;;
	oolite)
		status_led="oolite:red:system"
		;;
	qihoo-c301)
		status_led="qihoo:green:status"
		;;
	tew-632brp)
		status_led="tew-632brp:green:status"
		;;
	tew-673gru)
		status_led="trendnet:blue:wps"
		;;
	tew-712br|\
	tew-732br)
		status_led="trendnet:green:power"
		;;
	tl-mr3020)
		status_led="tp-link:green:wps"
		;;
	tl-wa750re)
		status_led="tp-link:orange:re"
		;;
	tl-wa850re)
		status_led="tp-link:blue:re"
		;;
	tl-wa860re)
		status_led="tp-link:green:power"
		;;
	tl-mr3220 | \
	tl-mr3220-v2 | \
	tl-mr3420 | \
	tl-mr3420-v2 | \
	tl-wa701nd-v2 | \
	tl-wa801nd-v2 | \
	tl-wa901nd | \
	tl-wa901nd-v2 | \
	tl-wa901nd-v3 | \
	tl-wdr3320-v2 | \
	tl-wdr3500 | \
	tl-wr1041n-v2 | \
	tl-wr1043nd | \
	tl-wr1043nd-v2 | \
	tl-wr741nd | \
	tl-wr741nd-v4 | \
	tl-wr841n-v1 | \
	tl-wr841n-v7 | \
	tl-wr841n-v8 | \
	tl-wa830re-v2 | \
	tl-wr842n-v2 | \
	tl-wr941nd | \
	tl-wr941nd-v5)
		status_led="tp-link:green:system"
		;;
	archer-c5 | \
	archer-c7 | \
	tl-wdr4900-v2 | \
	tl-mr10u | \
	tl-mr12u | \
	tl-mr13u | \
	tl-wdr4300 | \
	tl-wr703n | \
	tl-wr710n | \
	tl-wr720n-v3)
		status_led="tp-link:blue:system"
		;;
	tl-wr841n-v9)
		status_led="tp-link:green:qss"
		;;
	tl-wr2543n)
		status_led="tp-link:green:wps"
		;;
	tl-wdr6500-v2)
		status_led="tp-link:white:system"
		;;
	tube2h)
		status_led="alfa:green:signal4"
		;;
	unifi)
		status_led="ubnt:green:dome"
		;;
	uap-pro)
		status_led="ubnt:white:dome"
		;;
	unifi-outdoor-plus)
		status_led="ubnt:white:front"
		;;
	airgateway | \
	airgatewaypro)
		status_led="ubnt:white:status"
		;;
	whr-g301n | \
	whr-hp-g300n | \
	whr-hp-gn | \
	wzr-hp-g300nh)
		status_led="buffalo:green:router"
		;;
	wlae-ag300n)
		status_led="buffalo:green:status"
		;;
	wzr-hp-ag300h | \
	wzr-hp-g300nh2)
		status_led="buffalo:red:diag"
		;;
	r6100 | \
	wndap360 | \
	wndr3700 | \
	wndr3700v4 | \
	wndr4300 | \
	wnr2000 | \
	wnr2200 |\
	wnr612-v2 |\
	wnr1000-v2)
		status_led="netgear:green:power"
		;;
	wp543)
		status_led="wp543:green:diag"
		;;
	wpj344)
		status_led="wpj344:green:status"
		;;
	wpj531)
		status_led="wpj531:green:sig3"
		;;
	wpj558)
		status_led="wpj558:green:sig3"
		;;
	wrt400n)
		status_led="wrt400n:blue:wps"
		;;
	wrt160nl)
		status_led="wrt160nl:blue:wps"
		;;
	zcn-1523h-2 | zcn-1523h-5)
		status_led="zcn-1523h:amber:init"
		;;
	wlr8100)
		status_led="sitecom:amber:status"
		;;
	esac
}

set_state() {
	get_status_led

	case "$1" in
	preinit)
		status_led_blink_preinit
		;;
	failsafe)
		status_led_blink_failsafe
		;;
	preinit_regular)
		status_led_blink_preinit_regular
		;;
	done)
		status_led_on
		case $(ar71xx_board_name) in
		qihoo-c301)
			local n=$(fw_printenv activeregion | cut -d = -f 2)
			fw_setenv "image${n}trynum" 0
			;;
		esac
		;;
	esac
}