Skip to content

Commit b15b9df

Browse files
committed
feat: add discard/erase block support
1 parent b771bea commit b15b9df

17 files changed

+1136
-295
lines changed

src/machine/machine_rp2350_usb.go

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,14 @@ func initEndpoint(ep, config uint32) {
142142
offset := ep*2*usbBufferLen + 0x100
143143
val |= offset
144144

145+
// Bulk and interrupt endpoints must have their Packet ID reset to DATA0 when un-stalled
146+
if config&(usb.ENDPOINT_TYPE_BULK|usb.ENDPOINT_TYPE_INTERRUPT) != 0 {
147+
epXPIDReset[ep] = true
148+
} else {
149+
// In case we're reconfiguring an endpoint, change the PID reset behavior
150+
epXPIDReset[ep] = false
151+
}
152+
145153
switch config {
146154
case usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointIn:
147155
val |= usbEpControlEndpointTypeInterrupt
@@ -248,11 +256,11 @@ func handleEndpointRx(ep uint32) []byte {
248256
}
249257

250258
func handleEndpointRxComplete(ep uint32) {
251-
SetEPDataPID(ep, !epXdata0[ep])
259+
setEPDataPID(ep, !epXdata0[ep])
252260
}
253261

254262
// Set the USB endpoint Packet ID to DATA0 or DATA1
255-
func SetEPDataPID(ep uint32, dataOne bool) {
263+
func setEPDataPID(ep uint32, dataOne bool) {
256264
epXdata0[ep&0x7F] = dataOne
257265
if epXdata0[ep] || ep == 0 {
258266
_usbDPSRAM.EPxBufferControl[ep].Out.SetBits(usbBuf0CtrlData1Pid)
@@ -307,12 +315,20 @@ func SetStallEPOut(ep uint32) {
307315
func ClearStallEPIn(ep uint32) {
308316
val := uint32(usbBuf0CtrlStall)
309317
_usbDPSRAM.EPxBufferControl[ep&0x7F].In.ClearBits(val)
318+
if epXPIDReset[ep] {
319+
// Reset the PID to DATA0
320+
setEPDataPID(ep, false)
321+
}
310322
}
311323

312324
// Clear the endpoint stall bit on a USB OUT endpoint
313325
func ClearStallEPOut(ep uint32) {
314326
val := uint32(usbBuf0CtrlStall)
315327
_usbDPSRAM.EPxBufferControl[ep&0x7F].Out.ClearBits(val)
328+
if epXPIDReset[ep] {
329+
// Reset the PID to DATA0
330+
setEPDataPID(ep, false)
331+
}
316332
}
317333

318334
type usbDPSRAM struct {
@@ -339,9 +355,10 @@ type usbBuffer struct {
339355
}
340356

341357
var (
342-
_usbDPSRAM = (*usbDPSRAM)(unsafe.Pointer(uintptr(0x50100000)))
343-
epXdata0 [16]bool
344-
setupBytes [8]byte
358+
_usbDPSRAM = (*usbDPSRAM)(unsafe.Pointer(uintptr(0x50100000)))
359+
epXdata0 [16]bool
360+
epXPIDReset [16]bool
361+
setupBytes [8]byte
345362
)
346363

347364
func (d *usbDPSRAM) setupBytes() []byte {

src/machine/usb.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ var (
123123
usbTxHandler [usb.NumberOfEndpoints]func()
124124
usbRxHandler [usb.NumberOfEndpoints]func([]byte)
125125
usbSetupHandler [usb.NumberOfInterfaces]func(usb.Setup) bool
126+
usbStallHandler [usb.NumberOfEndpoints]func(usb.Setup) bool
126127

127128
endPoints = []uint32{
128129
usb.CONTROL_ENDPOINT: usb.ENDPOINT_TYPE_CONTROL,
@@ -214,7 +215,11 @@ func handleStandardSetup(setup usb.Setup) bool {
214215
if setup.WValueL == 1 { // DEVICEREMOTEWAKEUP
215216
isRemoteWakeUpEnabled = false
216217
} else if setup.WValueL == 0 { // ENDPOINTHALT
217-
isEndpointHalt = false
218+
if usbStallHandler[setup.WIndex&0x7F] != nil {
219+
return usbStallHandler[setup.WIndex&0x7F](setup)
220+
} else {
221+
isEndpointHalt = false
222+
}
218223
}
219224
SendZlp()
220225
return true
@@ -223,7 +228,11 @@ func handleStandardSetup(setup usb.Setup) bool {
223228
if setup.WValueL == 1 { // DEVICEREMOTEWAKEUP
224229
isRemoteWakeUpEnabled = true
225230
} else if setup.WValueL == 0 { // ENDPOINTHALT
226-
isEndpointHalt = true
231+
if usbStallHandler[setup.WIndex&0x7F] != nil {
232+
return usbStallHandler[setup.WIndex&0x7F](setup)
233+
} else {
234+
isEndpointHalt = true
235+
}
227236
}
228237
SendZlp()
229238
return true
@@ -322,6 +331,9 @@ func ConfigureUSBEndpoint(desc descriptor.Descriptor, epSettings []usb.EndpointC
322331
usbRxHandler[ep.Index] = ep.RxHandler
323332
}
324333
}
334+
if ep.StallHandler != nil {
335+
usbStallHandler[ep.Index] = ep.StallHandler
336+
}
325337
}
326338

327339
for _, s := range setup {

src/machine/usb/config.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
package usb
22

33
type EndpointConfig struct {
4-
Index uint8
5-
IsIn bool
6-
TxHandler func()
7-
RxHandler func([]byte)
8-
Type uint8
4+
Index uint8
5+
IsIn bool
6+
TxHandler func()
7+
RxHandler func([]byte)
8+
StallHandler func(Setup) bool
9+
Type uint8
910
}
1011

1112
type SetupConfig struct {

src/machine/usb/descriptor/endpoint.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,3 +150,7 @@ func (d EndpointType) MaxPacketSize(v uint16) {
150150
func (d EndpointType) Interval(v uint8) {
151151
d.data[6] = byte(v)
152152
}
153+
154+
func (d EndpointType) GetMaxPacketSize() uint16 {
155+
return binary.LittleEndian.Uint16(d.data[4:6])
156+
}

src/machine/usb/msc/cbw.go

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
package msc
22

33
import (
4+
"encoding/binary"
45
"machine/usb/msc/csw"
56
"machine/usb/msc/scsi"
67
)
78

89
const (
9-
cbwMsgLen = 31 // Command Block Wrapper (CBW) message length
10+
cbwMsgLen = 31 // Command Block Wrapper (CBW) message length
11+
Signature = 0x43425355 // "USBC" in little endian
1012
)
1113

1214
type CBW struct {
@@ -22,15 +24,15 @@ func (c *CBW) validLength() bool {
2224
}
2325

2426
func (c *CBW) validSignature() bool {
25-
return c.Data[0] == 0x55 && c.Data[1] == 0x53 && c.Data[2] == 0x42 && c.Data[3] == 0x43
27+
return binary.LittleEndian.Uint32(c.Data[:4]) == Signature
2628
}
2729

2830
func (c *CBW) scsiCmd() scsi.Cmd {
2931
return scsi.Cmd{Data: c.Data[15:]}
3032
}
3133

3234
func (c *CBW) transferLength() uint32 {
33-
return uint32(c.Data[8]) | uint32(c.Data[9])<<8 | uint32(c.Data[10])<<16 | uint32(c.Data[11])<<24
35+
return binary.LittleEndian.Uint32(c.Data[8:12])
3436
}
3537

3638
// isIn returns true if the command direction is from the device to the host.
@@ -44,21 +46,12 @@ func (c *CBW) isOut() bool {
4446
}
4547

4648
func (c *CBW) CSW(status csw.Status, residue uint32, b []byte) {
47-
// Signature: 53425355h (little endian)
48-
b[3] = 0x53
49-
b[2] = 0x42
50-
b[1] = 0x53
51-
b[0] = 0x55
52-
// Tag:
53-
b[4] = c.Data[4]
54-
b[5] = c.Data[5]
55-
b[6] = c.Data[6]
56-
b[7] = c.Data[7]
49+
// Signature: "USBS" 53425355h (little endian)
50+
binary.LittleEndian.PutUint32(b[:4], csw.Signature)
51+
// Tag: (same as CBW)
52+
copy(b[4:8], c.Data[4:8])
5753
// Data Residue: (untransferred bytes)
58-
b[8] = byte(residue)
59-
b[9] = byte(residue >> 8)
60-
b[10] = byte(residue >> 16)
61-
b[11] = byte(residue >> 24)
54+
binary.LittleEndian.PutUint32(b[8:12], residue)
6255
// Status:
6356
b[12] = byte(status)
6457
}

src/machine/usb/msc/csw/csw.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@ const (
99
)
1010

1111
const (
12-
MsgLen = 13
12+
MsgLen = 13
13+
Signature = 0x53425355 // "USBS" in little endian
1314
)

src/machine/usb/msc/disk.go

Lines changed: 43 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
package msc
22

3-
type Disk interface {
4-
Ready() bool
5-
ReadOnly() bool
6-
BlockCount() uint32
7-
BlockSize() uint32
8-
Read(offset uint32, buffer []byte) (uint32, error)
9-
Write(offset uint32, buffer []byte) (uint32, error)
10-
}
3+
import (
4+
"encoding/binary"
5+
"machine"
6+
)
7+
8+
var _ machine.BlockDevice = (*DefaultDisk)(nil)
119

1210
// DefaultDisk is a placeholder disk implementation
1311
type DefaultDisk struct {
@@ -18,36 +16,58 @@ func NewDefaultDisk() *DefaultDisk {
1816
return &DefaultDisk{}
1917
}
2018

21-
func (d *DefaultDisk) Ready() bool {
22-
return true
19+
func (d *DefaultDisk) Size() int64 {
20+
return 4096 * int64(d.WriteBlockSize()) // 2MB
2321
}
2422

25-
func (d *DefaultDisk) ReadOnly() bool {
26-
return false
23+
func (d *DefaultDisk) WriteBlockSize() int64 {
24+
return 512 // 512 bytes
2725
}
2826

29-
func (d *DefaultDisk) BlockCount() uint32 {
30-
return 4096 // 2MB
27+
func (d *DefaultDisk) EraseBlockSize() int64 {
28+
return 2048 // 4 blocks of 512 bytes
3129
}
3230

33-
func (d *DefaultDisk) BlockSize() uint32 {
34-
return 512 // 512 bytes
31+
func (d *DefaultDisk) EraseBlocks(startBlock, numBlocks int64) error {
32+
return nil
3533
}
3634

37-
func (d *DefaultDisk) Read(offset uint32, buffer []byte) (uint32, error) {
35+
func (d *DefaultDisk) ReadAt(buffer []byte, offset int64) (int, error) {
3836
n := uint8(offset)
3937
for i := range buffer {
4038
n++
4139
buffer[i] = n
4240
}
43-
return uint32(len(buffer)), nil
41+
return len(buffer), nil
4442
}
4543

46-
func (d *DefaultDisk) Write(offset uint32, buffer []byte) (uint32, error) {
47-
return uint32(len(buffer)), nil
44+
func (d *DefaultDisk) WriteAt(buffer []byte, offset int64) (int, error) {
45+
return len(buffer), nil
4846
}
4947

50-
// RegisterDisk registers a disk provider with the MSC driver
51-
func (m *msc) RegisterDisk(disk Disk) {
52-
m.disk = disk
48+
// RegisterBlockDevice registers a BlockDevice provider with the MSC driver
49+
func (m *msc) RegisterBlockDevice(dev machine.BlockDevice) {
50+
m.dev = dev
51+
52+
// Set VPD UNMAP fields
53+
for i := range vpdPages {
54+
if vpdPages[i].PageCode == 0xb0 {
55+
// 0xb0 - 5.4.5 Block Limits VPD page (B0h)
56+
if len(vpdPages[i].Data) >= 28 {
57+
// Set the OPTIMAL UNMAP GRANULARITY (write blocks per erase block)
58+
granularity := uint32(dev.EraseBlockSize()) / uint32(dev.WriteBlockSize())
59+
binary.BigEndian.PutUint32(vpdPages[i].Data[24:28], granularity)
60+
}
61+
/* TODO: Add method for working out the optimal unmap granularity alignment
62+
if len(vpdPages[i].Data) >= 32 {
63+
// Set the UNMAP GRANULARITY ALIGNMENT (first sector of first full erase block)
64+
// The unmap granularity alignment is used to calculate an optimal unmap request starting LBA as follows:
65+
// optimal unmap request starting LBA = (n * OPTIMAL UNMAP GRANULARITY) + UNMAP GRANULARITY ALIGNMENT
66+
// where n is zero or any positive integer value
67+
// https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf
68+
}
69+
*/
70+
break
71+
}
72+
}
5373
}

src/machine/usb/msc/fakefs/fakefs.go

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package fakefs
2+
3+
type MockFS interface {
4+
ReadAt(p []byte, off int64) (n int, err error)
5+
WriteAt(p []byte, off int64) (n int, err error)
6+
ReadOnly() bool
7+
/* FIXME: Cleanup?
8+
SectorCount() uint32
9+
SectorSize() uint16
10+
*/
11+
}
12+
13+
type FakeFS struct {
14+
fs MockFS
15+
ready bool
16+
}
17+
18+
func NewFakeFS() *FakeFS {
19+
// FIXME: Initialize the fake FAT12 file system
20+
return &FakeFS{fs: NewFAT12(), ready: true}
21+
}
22+
23+
func (fs *FakeFS) TestUnitReady() bool {
24+
// Check if the disk is ready
25+
return fs.ready
26+
}
27+
28+
func (fs *FakeFS) SetReady(ready bool) {
29+
// Set the disk ready state
30+
fs.ready = ready
31+
}
32+
33+
func (fs *FakeFS) Read(offset uint32, buffer []byte) (uint32, error) {
34+
return uint32(len(buffer)), nil // FIXME: Cleanup
35+
// Read data from the file system
36+
n, err := fs.fs.ReadAt(buffer, int64(offset))
37+
if err != nil {
38+
return 0, err
39+
}
40+
return uint32(n), nil
41+
}
42+
43+
func (fs *FakeFS) Write(offset uint32, buffer []byte) (uint32, error) {
44+
return uint32(len(buffer)), nil // FIXME: Cleanup
45+
// Write data to the file system
46+
n, err := fs.fs.WriteAt(buffer, int64(offset))
47+
if err != nil {
48+
return 0, err
49+
}
50+
return uint32(n), nil
51+
}
52+
53+
/* FIXME: Cleanup
54+
func (fs *FakeFS) ReadCapacity() (uint32, uint32) {
55+
// Return the total number of blocks and block size
56+
return 0, 0 // FIXME: Implement finding actual values
57+
}
58+
59+
func (fs *FakeFS) ReadFormatCapacity() (uint32, uint32) {
60+
// Return the total number of blocks and block size
61+
return 0, 0 // FIXME: Implement finding actual values
62+
}
63+
64+
func (fs *FakeFS) Inquiry() ([]byte, error) {
65+
// Return the inquiry data
66+
return nil, nil // FIXME: Implement finding actual values
67+
}
68+
*/
69+
70+
func (fs *FakeFS) ReadOnly() bool {
71+
// If the file system is read-only, return true to indicate the hardware is read-only also
72+
return fs.fs.ReadOnly()
73+
}
74+
75+
func (fs *FakeFS) BlockCount() uint32 {
76+
// Return the total number of blocks
77+
return 4096 // FIXME: Implement finding actual values
78+
}
79+
80+
func (fs *FakeFS) BlockSize() uint32 {
81+
// Return the block size
82+
return 512 // FIXME: Implement finding actual values
83+
}

0 commit comments

Comments
 (0)