Linux USB Gadget - 장치 매 거 진
struct usb_request {
void *buf;
unsigned length;
dma_addr_t dma;
unsigned no_interrupt:1;
unsigned zero:1;
unsigned short_not_ok:1;
void (*complete)(struct usb_ep *ep,
struct usb_request *req);
void *context;
struct list_head list;
int status;
unsigned actual;
};
(1) buf 필드 는 데 이 터 를 받 아들 이거 나 보 낼 곳 이 고 length 는 데이터 의 길 이 를 대표 합 니 다.(2) dma 는 dmaaddr_t 유형의 DMA 전송 과 관련 이 있 습 니 다.s3c 2440 의 USB 장치 컨트롤 러 는 DMA 조작 을 지원 하지만 바 텀 UDC 구동 이 이 루어 지지 않 았 기 때문에 이 필드 에 신경 쓰 지 않 아 도 됩 니 다.
(3) 세 개의 도 메 인 은 각각 대표 한다.
(4)(*complete)(struct usb_ep *ep, struct usb_request *req); 이것 은 반전 함수 입 니 다. 터미널 에서 urt 를 처리 할 때 호출 하 는 것 이 매우 중요 합 니 다.
(5)context
(6) list 역할 은 자신 을 터미널 링크 에 연결 하 는 것 이다.
(7) status 상태
(8) actual 실제 전송 바이트
USB 장치 매 거
urt 를 분석 하면 실제 호스트 에서 USB 장 치 를 식별 하 는 가장 중요 한 장치 에 들 어 갑 니 다.여 기 는 주로 장치 가 호스트 에 어떻게 해당 하 는 지 분석 하고 호스트 가 어떻게 이런 조작 을 완성 하 는 지 에 대해 호스트 컨트롤 러 를 찾 아 연구 합 니 다.우선 USB 장치 매 거 진 을 돌 이 켜 보면 그 절 차 를 완성 해 야 합 니 다.
(1) 장치 가 호스트 에 삽입 되 고 호스트 가 장 치 를 감지 합 니 다.리 셋 장치
(2) 호스트 가 장치 제어 점 에 Get 보 내기Descriptor 는 장치 의 기본 파이프 크기 를 알 수 있 습 니 다.
(3) 호스트 가 주 소 를 지정 하여 set 를 보 냅 니 다.address 표준 요청 장치 주소
(4) 호스트 가 새로운 주 소 를 사용 하여 get 을 다시 보 냅 니 다.설명자
(5) 호스트 에 USB 장치 드라이버 불 러 오기
(6) USB 장치 구동 재 전송 SetConfuration 표준 장치 요청 설정 장치
이상 은 USB 장치 가 매 거 진 과정 입 니 다.USB 장 치 는 호스트 의 요구 가 정확 해 야 장치 매 거 진 을 순조롭게 완성 할 수 있 습 니 다.우 리 는 USB 가 주종 식 버스 구조 라 는 것 을 알 고 있 으 며, 모든 통신 은 호스트 에서 시작 되 며, 설 비 는 조금의 자주 권 도 없다.s3c 2440 USB 장치 컨트롤 러 는 호스트 가 USB 장치 에 가방 을 보 낼 때 USB 장치 컨트롤 러 가 중단 된다.전송 오류 가 발생 했 을 때 도 중단 형식 으로 알려 줍 니 다.따라서 USB 장치 컨트롤 러 의 중단 을 이해 하 는 것 이 USB 통신 과정 을 이해 하 는 관건 이다.s3c 2410udc. c 는 장치 가 초기 화 되 었 을 때 인 터 럽 트 처리 프로그램 을 등 록 했 습 니 다.
static irqreturn_t s3c2410_udc_irq(int dummy, void *_dev)
{
// :retval = request_irq(IRQ_USBD, s3c2410_udc_irq, IRQF_DISABLED, gadget_name, udc); udc struct s3c2410_udc
// , USB s3c2410 , struct s3c2410_udc 。 。
struct s3c2410_udc *dev = _dev;
int usb_status;
int usbd_status;
int pwr_reg;
int ep0csr;
int i;
u32 idx;
unsigned long flags;
// , dev , 。 ,
spin_lock_irqsave(&dev->lock, flags);
/* Driver connected ? */
// USB ,
if (!dev->driver) {
/* Clear interrupts */
udc_write(udc_read(S3C2410_UDC_USB_INT_REG),
S3C2410_UDC_USB_INT_REG);
udc_write(udc_read(S3C2410_UDC_EP_INT_REG),
S3C2410_UDC_EP_INT_REG);
}
//s3c2440 USB , , 。 , 。S3C2410_UDC_INDEX_REG
/* Save index */
idx = udc_read(S3C2410_UDC_INDEX_REG);
//
/* Read status registers */
usb_status = udc_read(S3C2410_UDC_USB_INT_REG);
usbd_status = udc_read(S3C2410_UDC_EP_INT_REG);
pwr_reg = udc_read(S3C2410_UDC_PWR_REG);
//
udc_writeb(base_addr, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);
ep0csr = udc_read(S3C2410_UDC_IN_CSR1_REG);
//
dprintk(DEBUG_NORMAL, "usbs=%02x, usbds=%02x, pwr=%02x ep0csr=%02x
",
usb_status, usbd_status, pwr_reg, ep0csr);
/*
* Now, handle interrupts. There's two types :
* - Reset, Resume, Suspend coming -> usb_int_reg
* - EP -> ep_int_reg
*/
// , (1)
/* RESET */
if (usb_status & S3C2410_UDC_USBINT_RESET) {
/* two kind of reset :
* - reset start -> pwr reg = 8
* - reset end -> pwr reg = 0
**/
dprintk(DEBUG_NORMAL, "USB reset csr %x pwr %x
",
ep0csr, pwr_reg);
dev->gadget.speed = USB_SPEED_UNKNOWN;
udc_write(0x00, S3C2410_UDC_INDEX_REG);
udc_write((dev->ep[0].ep.maxpacket & 0x7ff) >> 3,
S3C2410_UDC_MAXP_REG);
dev->address = 0;
dev->ep0state = EP0_IDLE;
dev->gadget.speed = USB_SPEED_FULL;
/* clear interrupt */
udc_write(S3C2410_UDC_USBINT_RESET,
S3C2410_UDC_USB_INT_REG);
udc_write(idx, S3C2410_UDC_INDEX_REG);
spin_unlock_irqrestore(&dev->lock, flags);
return IRQ_HANDLED;
}
/* RESUME */
if (usb_status & S3C2410_UDC_USBINT_RESUME) {
dprintk(DEBUG_NORMAL, "USB resume
");
/* clear interrupt */
udc_write(S3C2410_UDC_USBINT_RESUME,
S3C2410_UDC_USB_INT_REG);
if (dev->gadget.speed != USB_SPEED_UNKNOWN
&& dev->driver
&& dev->driver->resume)
dev->driver->resume(&dev->gadget);
}
/* SUSPEND */
if (usb_status & S3C2410_UDC_USBINT_SUSPEND) {
dprintk(DEBUG_NORMAL, "USB suspend
");
/* clear interrupt */
udc_write(S3C2410_UDC_USBINT_SUSPEND,
S3C2410_UDC_USB_INT_REG);
if (dev->gadget.speed != USB_SPEED_UNKNOWN
&& dev->driver
&& dev->driver->suspend)
dev->driver->suspend(&dev->gadget);
dev->ep0state = EP0_IDLE;
}
/* EP */
/* control traffic */
/* check on ep0csr != 0 is not a good idea as clearing in_pkt_ready
* generate an interrupt
*/
if (usbd_status & S3C2410_UDC_INT_EP0) {
dprintk(DEBUG_VERBOSE, "USB ep0 irq
");
/* Clear the interrupt bit by setting it to 1 */
udc_write(S3C2410_UDC_INT_EP0, S3C2410_UDC_EP_INT_REG);
s3c2410_udc_handle_ep0(dev);
}
/* endpoint data transfers */
for (i = 1; i < S3C2410_ENDPOINTS; i++) {
u32 tmp = 1 << i;
if (usbd_status & tmp) {
dprintk(DEBUG_VERBOSE, "USB ep%d irq
", i);
/* Clear the interrupt bit by setting it to 1 */
udc_write(tmp, S3C2410_UDC_EP_INT_REG);
s3c2410_udc_handle_ep(&dev->ep[i]);
}
}
dprintk(DEBUG_VERBOSE, "irq: %d s3c2410_udc_done.
", IRQ_USBD);
/* Restore old index */
udc_write(idx, S3C2410_UDC_INDEX_REG);
spin_unlock_irqrestore(&dev->lock, flags);
return IRQ_HANDLED;
}
이 함 수 는 인 터 럽 트 유형 에 따라 처 리 됩 니 다.장치 가 매 거 될 때 USB 장치 컨트롤 러 가 발생 하 는 중단 은 모두 점 0 이 므 로 s3c 2410 을 호출 합 니 다.udc_handle_ep0 (dev) 함수.이 함수 도 s3c 2410 로 정의 합 니 다.udc. c 에서 다음 과 같 습 니 다.static void s3c2410_udc_handle_ep0(struct s3c2410_udc *dev)
{
u32 ep0csr;
struct s3c2410_ep *ep = &dev->ep[0];
struct s3c2410_request *req;
struct usb_ctrlrequest crq;
if (list_empty(&ep->queue))
req = NULL;
else
req = list_entry(ep->queue.next, struct s3c2410_request, queue);
/* We make the assumption that S3C2410_UDC_IN_CSR1_REG equal to
* S3C2410_UDC_EP0_CSR_REG when index is zero */
udc_write(0, S3C2410_UDC_INDEX_REG);
ep0csr = udc_read(S3C2410_UDC_IN_CSR1_REG);
dprintk(DEBUG_NORMAL, "ep0csr %x ep0state %s
",
ep0csr, ep0states[dev->ep0state]);
/* clear stall status */
if (ep0csr & S3C2410_UDC_EP0_CSR_SENTSTL) {
s3c2410_udc_nuke(dev, ep, -EPIPE);
dprintk(DEBUG_NORMAL, "... clear SENT_STALL ...
");
s3c2410_udc_clear_ep0_sst(base_addr);
dev->ep0state = EP0_IDLE;
return;
}
/* clear setup end */
if (ep0csr & S3C2410_UDC_EP0_CSR_SE) {
dprintk(DEBUG_NORMAL, "... serviced SETUP_END ...
");
s3c2410_udc_nuke(dev, ep, 0);
s3c2410_udc_clear_ep0_se(base_addr);
dev->ep0state = EP0_IDLE;
}
switch (dev->ep0state) {
case EP0_IDLE:
s3c2410_udc_handle_ep0_idle(dev, ep, &crq, ep0csr);
break;
case EP0_IN_DATA_PHASE: /* GET_DESCRIPTOR etc */
dprintk(DEBUG_NORMAL, "EP0_IN_DATA_PHASE ... what now?
");
if (!(ep0csr & S3C2410_UDC_EP0_CSR_IPKRDY) && req) {
s3c2410_udc_write_fifo(ep, req);
}
break;
case EP0_OUT_DATA_PHASE: /* SET_DESCRIPTOR etc */
dprintk(DEBUG_NORMAL, "EP0_OUT_DATA_PHASE ... what now?
");
if ((ep0csr & S3C2410_UDC_EP0_CSR_OPKRDY) && req ) {
s3c2410_udc_read_fifo(ep,req);
}
break;
case EP0_END_XFER:
dprintk(DEBUG_NORMAL, "EP0_END_XFER ... what now?
");
dev->ep0state = EP0_IDLE;
break;
case EP0_STALL:
dprintk(DEBUG_NORMAL, "EP0_STALL ... what now?
");
dev->ep0state = EP0_IDLE;
break;
}
}
이 함 수 를 보기 전에 struct s3c 2410ep 이 데이터 구 조 는 s3c 2410 usb 장치 컨트롤 러 의 단점 을 대표 합 니 다.구 조 는 다음 과 같다. struct s3c2410_ep {
struct list_head queue;
unsigned long last_io; /* jiffies timestamp */
struct usb_gadget *gadget;
struct s3c2410_udc *dev;
const struct usb_endpoint_descriptor *desc;
struct usb_ep ep;
u8 num;
unsigned short fifo_size;
u8 bEndpointAddress;
u8 bmAttributes;
unsigned halted : 1;
unsigned already_seen : 1;
unsigned setup_stage : 1;
};
이 구조의 구성원 일 부 는 정 의 를 내 릴 때 정적 으로 초기 화 되 고 점 0 은 정 의 를 내 릴 때 다음 과 같이 초기 화 됩 니 다. .ep[0] = {
.num = 0,
.ep = {
.name = ep0name,
.ops = &s3c2410_ep_ops,
.maxpacket = EP0_FIFO_SIZE,
},
.dev = &memory,
},
struct s3c 2410 보고ep 구조 후 s3c 2410 분석udc_handle_이 함수함수 우선 ep 의 queue 가 비어 있 는 지 판단 합 니 다. 이 필드 는 struct s3c 2410 을 연결 합 니 다.request 구조의 링크, struct s3c 2410request 는 struct usbrequest 의 간단 한 패 키 징 은 usb 전송 을 대표 합 니 다.비어 있 지 않 으 면 이 구성원 에 게 req 변 수 를 할당 합 니 다.다음은 터미널 0 의 상태 레지스터 EP0 읽 기CSR, 이 레지스터 는 터미널 0 의 상 태 를 반영 합 니 다.점 0 의 상 태 를 ep0csr 부분 변수 에 읽 습 니 다.이 때 인 터 럽 트 처리 프로그램 에서USB 장 치 를 매 거 하 는 과정 에서 가장 먼저 발생 하 는 중단 은 리 셋 이다.그리고 USB 호스트 는 장치 설명 자 를 얻 기 위해 제어 전송 을 시작 합 니 다.이 제어 전송 은 Get표준 장치 요청 을 설명 합 니 다.우 리 는 USB 제어 전송 은 데이터 전송 이 세 단계 로 나 뉘 고 데이터 전송 이 없 는 것 은 두 단계 로 나 뉜 다 는 것 을 안다.그리고 GetDescriptor 는 데이터 전송 이 있 습 니 다. USB 장 치 는 장치 설명 기 호 를 되 돌려 야 합 니 다.그래서 세 가지 단계 가 있다. 그것 이 바로 구축 단계, 데이터 단계, 상태 단계 이다.구축 단 계 는 세 개의 USB 패 킷 으로 나 뉜 다. 각각 setup 패 킷, data 패 킷, 악수 패 킷 이다.구축 단계 가 끝나 면 data 패키지 의 데 이 터 는 터미널 0 의 FIFO 에 기록 되 고 s3c 2410 USB 장치 컨트롤 러 는 중단 되 며 이에 대응 하 는 EP0CSR 의 SETUPEND 자리 가 설 치 됩 니 다.이때 이 상 태 를 판단 할 수 있다.그 다음 에 해당 함 수 를 호출 하여 FIFO 에 있 는 데 이 터 를 읽 고 전송 을 제어 하 는 유형 으로 판단 한 다음 에 서로 다른 유형 에 대해 서로 다른 조작 을 하거나 데 이 터 를 받 아들 이거 나 데 이 터 를 보 냅 니 다.지금 GetDescriptor 이 USB 표준 요청 으로 s3c 2410 분석udc_handle_ep0 함수 에서 코드 실행:(1) 우선, 구축 단계 가 중단 되 고 다음 코드 를 실행 합 니 다.
if (ep0csr & S3C2410_UDC_EP0_CSR_SE) {
dprintk(DEBUG_NORMAL, "... serviced SETUP_END ...
");
s3c2410_udc_nuke(dev, ep, 0);
s3c2410_udc_clear_ep0_se(base_addr);
dev->ep0state = EP0_IDLE;
}
(2) 그리고 dev - > ep0state = EP0IDLE 는 다음 코드 를 실행 합 니 다. case EP0_IDLE:
s3c2410_udc_handle_ep0_idle(dev, ep, &crq, ep0csr);
break;
s3c2410_udc_handle_ep0_idle 함수 도 s3c 2410 로 정의udc. c 에서 다음 과 같 습 니 다.static void s3c2410_udc_handle_ep0_idle(struct s3c2410_udc *dev,
struct s3c2410_ep *ep,
struct usb_ctrlrequest *crq,
u32 ep0csr)
{
int len, ret, tmp;
/* start control request? */
if (!(ep0csr & S3C2410_UDC_EP0_CSR_OPKRDY))
return;
s3c2410_udc_nuke(dev, ep, -EPROTO);
len = s3c2410_udc_read_fifo_crq(crq);
if (len != sizeof(*crq)) {
dprintk(DEBUG_NORMAL, "setup begin: fifo READ ERROR"
" wanted %d bytes got %d. Stalling out...
",
sizeof(*crq), len);
s3c2410_udc_set_ep0_ss(base_addr);
return;
}
dprintk(DEBUG_NORMAL, "bRequest = %d bRequestType %d wLength = %d
",
crq->bRequest, crq->bRequestType, crq->wLength);
/* cope with automagic for some standard requests. */
dev->req_std = (crq->bRequestType & USB_TYPE_MASK)
== USB_TYPE_STANDARD;
dev->req_config = 0;
dev->req_pending = 1;
switch (crq->bRequest) {
case USB_REQ_SET_CONFIGURATION:
dprintk(DEBUG_NORMAL, "USB_REQ_SET_CONFIGURATION ...
");
if (crq->bRequestType == USB_RECIP_DEVICE) {
dev->req_config = 1;
s3c2410_udc_set_ep0_de_out(base_addr);
}
break;
case USB_REQ_SET_INTERFACE:
dprintk(DEBUG_NORMAL, "USB_REQ_SET_INTERFACE ...
");
if (crq->bRequestType == USB_RECIP_INTERFACE) {
dev->req_config = 1;
s3c2410_udc_set_ep0_de_out(base_addr);
}
break;
case USB_REQ_SET_ADDRESS:
dprintk(DEBUG_NORMAL, "USB_REQ_SET_ADDRESS ...
");
if (crq->bRequestType == USB_RECIP_DEVICE) {
tmp = crq->wValue & 0x7F;
dev->address = tmp;
udc_write((tmp | S3C2410_UDC_FUNCADDR_UPDATE),
S3C2410_UDC_FUNC_ADDR_REG);
s3c2410_udc_set_ep0_de_out(base_addr);
return;
}
break;
case USB_REQ_GET_STATUS:
dprintk(DEBUG_NORMAL, "USB_REQ_GET_STATUS ...
");
s3c2410_udc_clear_ep0_opr(base_addr);
if (dev->req_std) {
if (!s3c2410_udc_get_status(dev, crq)) {
return;
}
}
break;
case USB_REQ_CLEAR_FEATURE:
s3c2410_udc_clear_ep0_opr(base_addr);
if (crq->bRequestType != USB_RECIP_ENDPOINT)
break;
if (crq->wValue != USB_ENDPOINT_HALT || crq->wLength != 0)
break;
s3c2410_udc_set_halt(&dev->ep[crq->wIndex & 0x7f].ep, 0);
s3c2410_udc_set_ep0_de_out(base_addr);
return;
case USB_REQ_SET_FEATURE:
s3c2410_udc_clear_ep0_opr(base_addr);
if (crq->bRequestType != USB_RECIP_ENDPOINT)
break;
if (crq->wValue != USB_ENDPOINT_HALT || crq->wLength != 0)
break;
s3c2410_udc_set_halt(&dev->ep[crq->wIndex & 0x7f].ep, 1);
s3c2410_udc_set_ep0_de_out(base_addr);
return;
default:
s3c2410_udc_clear_ep0_opr(base_addr);
break;
}
if (crq->bRequestType & USB_DIR_IN)
dev->ep0state = EP0_IN_DATA_PHASE;
else
dev->ep0state = EP0_OUT_DATA_PHASE;
ret = dev->driver->setup(&dev->gadget, crq);
if (ret < 0) {
if (dev->req_config) {
dprintk(DEBUG_NORMAL, "config change %02x fail %d?
",
crq->bRequest, ret);
return;
}
if (ret == -EOPNOTSUPP)
dprintk(DEBUG_NORMAL, "Operation not supported
");
else
dprintk(DEBUG_NORMAL,
"dev->driver->setup failed. (%d)
", ret);
udelay(5);
s3c2410_udc_set_ep0_ss(base_addr);
s3c2410_udc_set_ep0_de_out(base_addr);
dev->ep0state = EP0_IDLE;
/* deferred i/o == no response yet */
} else if (dev->req_pending) {
dprintk(DEBUG_VERBOSE, "dev->req_pending... what now?
");
dev->req_pending=0;
}
dprintk(DEBUG_VERBOSE, "ep0state %s
", ep0states[dev->ep0state]);
}
이 함수 가 하 는 주요 작업 은 터미널 0 FIFO 의 데 이 터 를 읽 는 것 입 니 다. 여기 의 데 이 터 는 전송 을 제어 하 는 유형 입 니 다.그리고 switch 문 구 를 통 해 전송 을 제어 하 는 것 이 무엇 인지 판단 합 니 다.전송 을 제어 하 는 유형 에 따라 서로 다른 조작 을 사용한다.여기 서 우리 가 가설 한 것 은 Get 이다.Descriptor。그러면 switch 문 구 는 실행 되 지 않 고 아래 문 구 를 실행 합 니 다. 이것 은 데이터 전송 에 대한 제어 전송 입 니 다.Get_Descriptor 의 방향 은 IN 이기 때문에 dev - > ep0state = EP0IN_DATA_PHASE 장치 점 상태.그리고 다음 예상 을 수행 하 겠 습 니 다. ret = dev->driver->setup(&dev->gadget, crq);여기 dev - > driver - > setup 이 초기 화 되 었 습 니 다. coposite 입 니 다.setup, coposite. c 에서 다음 과 같이 정의 합 니 다.static int
composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
{
struct usb_composite_dev *cdev = get_gadget_data(gadget);
struct usb_request *req = cdev->req;
int value = -EOPNOTSUPP;
u16 w_index = le16_to_cpu(ctrl->wIndex);
u8 intf = w_index & 0xFF;
u16 w_value = le16_to_cpu(ctrl->wValue);
u16 w_length = le16_to_cpu(ctrl->wLength);
struct usb_function *f = NULL;
/* partial re-init of the response message; the function or the
* gadget might need to intercept e.g. a control-OUT completion
* when we delegate to it.
*/
req->zero = 0;
req->complete = composite_setup_complete;
req->length = USB_BUFSIZ;
gadget->ep0->driver_data = cdev;
switch (ctrl->bRequest) {
/* we handle all standard USB descriptors */
case USB_REQ_GET_DESCRIPTOR:
if (ctrl->bRequestType != USB_DIR_IN)
goto unknown;
switch (w_value >> 8) {
case USB_DT_DEVICE:
cdev->desc.bNumConfigurations =
count_configs(cdev, USB_DT_DEVICE);
value = min(w_length, (u16) sizeof cdev->desc);
memcpy(req->buf, &cdev->desc, value);
break;
case USB_DT_DEVICE_QUALIFIER:
if (!gadget_is_dualspeed(gadget))
break;
device_qual(cdev);
value = min_t(int, w_length,
sizeof(struct usb_qualifier_descriptor));
break;
case USB_DT_OTHER_SPEED_CONFIG:
if (!gadget_is_dualspeed(gadget))
break;
/* FALLTHROUGH */
case USB_DT_CONFIG:
value = config_desc(cdev, w_value);
if (value >= 0)
value = min(w_length, (u16) value);
break;
case USB_DT_STRING:
value = get_string(cdev, req->buf,
w_index, w_value & 0xff);
if (value >= 0)
value = min(w_length, (u16) value);
break;
}
break;
/* any number of configs can work */
case USB_REQ_SET_CONFIGURATION:
if (ctrl->bRequestType != 0)
goto unknown;
if (gadget_is_otg(gadget)) {
if (gadget->a_hnp_support)
DBG(cdev, "HNP available
");
else if (gadget->a_alt_hnp_support)
DBG(cdev, "HNP on another port
");
else
VDBG(cdev, "HNP inactive
");
}
spin_lock(&cdev->lock);
value = set_config(cdev, ctrl, w_value);
spin_unlock(&cdev->lock);
break;
case USB_REQ_GET_CONFIGURATION:
if (ctrl->bRequestType != USB_DIR_IN)
goto unknown;
if (cdev->config)
*(u8 *)req->buf = cdev->config->bConfigurationValue;
else
*(u8 *)req->buf = 0;
value = min(w_length, (u16) 1);
break;
/* function drivers must handle get/set altsetting; if there's
* no get() method, we know only altsetting zero works.
*/
case USB_REQ_SET_INTERFACE:
if (ctrl->bRequestType != USB_RECIP_INTERFACE)
goto unknown;
if (!cdev->config || w_index >= MAX_CONFIG_INTERFACES)
break;
f = cdev->config->interface[intf];
if (!f)
break;
if (w_value && !f->set_alt)
break;
value = f->set_alt(f, w_index, w_value);
break;
case USB_REQ_GET_INTERFACE:
if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE))
goto unknown;
if (!cdev->config || w_index >= MAX_CONFIG_INTERFACES)
break;
f = cdev->config->interface[intf];
if (!f)
break;
/* lots of interfaces only need altsetting zero... */
value = f->get_alt ? f->get_alt(f, w_index) : 0;
if (value < 0)
break;
*((u8 *)req->buf) = value;
value = min(w_length, (u16) 1);
break;
default:
unknown:
VDBG(cdev,
"non-core control req%02x.%02x v%04x i%04x l%d
",
ctrl->bRequestType, ctrl->bRequest,
w_value, w_index, w_length);
/* functions always handle their interfaces ... punt other
* recipients (endpoint, other, WUSB, ...) to the current
* configuration code.
*
* REVISIT it could make sense to let the composite device
* take such requests too, if that's ever needed: to work
* in config 0, etc.
*/
if ((ctrl->bRequestType & USB_RECIP_MASK)
== USB_RECIP_INTERFACE) {
f = cdev->config->interface[intf];
if (f && f->setup)
value = f->setup(f, ctrl);
else
f = NULL;
}
if (value < 0 && !f) {
struct usb_configuration *c;
c = cdev->config;
if (c && c->setup)
value = c->setup(c, ctrl);
}
goto done;
}
/* respond with data transfer before status phase? */
if (value >= 0) {
req->length = value;
req->zero = value < w_length;
value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
if (value < 0) {
DBG(cdev, "ep_queue --> %d
", value);
req->status = 0;
composite_setup_complete(gadget->ep0, req);
}
}
done:
/* device either stalls (value < 0) or reports success */
return value;
}
이 함 수 는 먼저 USB 제어 요청 의 각 필드 를 추출 한 다음 점 0 의 struct usb 를 초기 화 합 니 다.request 구조.완성 반전 함수 coposite 설정setup_complete。이 때 switch 문 구 를 통 해 어떤 제어 전송 인지 판단 합 니 다.예 를 들 어 여 기 는 GetDescriptor, 그리고 장치 가 매 거 졌 을 때 장치 설명자 의 8 개의 바이트 만 가 져 와 서 점 0 의 FIFO 깊이 를 알 수 있 습 니 다.그래서 다음 코드 실행: cdev->desc.bNumConfigurations =
count_configs(cdev, USB_DT_DEVICE);
value = min(w_length, (u16) sizeof cdev->desc);
memcpy(req->buf, &cdev->desc, value);
이 코드 는 장치 설명 자 를 req 의 버퍼 로 복사 하 는 것 입 니 다.그리고 다음 코드 를 실행 합 니 다: if (value >= 0) {
req->length = value;
req->zero = value < w_length;
value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
if (value < 0) {
DBG(cdev, "ep_queue --> %d
", value);
req->status = 0;
composite_setup_complete(gadget->ep0, req);
}
}
이 때 value 는 0 이 아니 기 때문에 if 안의 문 구 를 실행 합 니 다.usb_ep_quue 함수 의 주요 역할 은 req 의 데 이 터 를 FIFO 에 기록 하 는 것 입 니 다.함 수 는 다음 과 같이 정의 합 니 다.static int s3c2410_udc_queue(struct usb_ep *_ep, struct usb_request *_req,
gfp_t gfp_flags)
{
struct s3c2410_request *req = to_s3c2410_req(_req);
struct s3c2410_ep *ep = to_s3c2410_ep(_ep);
struct s3c2410_udc *dev;
u32 ep_csr = 0;
int fifo_count = 0;
unsigned long flags;
if (unlikely (!_ep || (!ep->desc && ep->ep.name != ep0name))) {
dprintk(DEBUG_NORMAL, "%s: invalid args
", __func__);
return -EINVAL;
}
dev = ep->dev;
if (unlikely (!dev->driver
|| dev->gadget.speed == USB_SPEED_UNKNOWN)) {
return -ESHUTDOWN;
}
//
local_irq_save (flags);
if (unlikely(!_req || !_req->complete
|| !_req->buf || !list_empty(&req->queue))) {
if (!_req)
dprintk(DEBUG_NORMAL, "%s: 1 X X X
", __func__);
else {
dprintk(DEBUG_NORMAL, "%s: 0 %01d %01d %01d
",
__func__, !_req->complete,!_req->buf,
!list_empty(&req->queue));
}
local_irq_restore(flags);
return -EINVAL;
}
_req->status = -EINPROGRESS;
_req->actual = 0;
//
dprintk(DEBUG_VERBOSE, "%s: ep%x len %d
",
__func__, ep->bEndpointAddress, _req->length);
if (ep->bEndpointAddress) { // , 0 else
udc_write(ep->bEndpointAddress & 0x7F, S3C2410_UDC_INDEX_REG);
ep_csr = udc_read((ep->bEndpointAddress & USB_DIR_IN)
? S3C2410_UDC_IN_CSR1_REG
: S3C2410_UDC_OUT_CSR1_REG);
fifo_count = s3c2410_udc_fifo_count_out();
} else { // 0
udc_write(0, S3C2410_UDC_INDEX_REG);
ep_csr = udc_read(S3C2410_UDC_IN_CSR1_REG);
fifo_count = s3c2410_udc_fifo_count_out(); // fifo
}
/* kickstart this i/o queue? */
if (list_empty(&ep->queue) && !ep->halted) { // urt , , , ,
if (ep->bEndpointAddress == 0 /* ep0 */) {
switch (dev->ep0state) {
case EP0_IN_DATA_PHASE: // Get_Descriptor, s3c2410_udc_handle_ep0_idle dev->ep0state EP0_IN_DATA_PHASE
if (!(ep_csr&S3C2410_UDC_EP0_CSR_IPKRDY)
&& s3c2410_udc_write_fifo(ep,
req)) {
dev->ep0state = EP0_IDLE;
req = NULL;
}
break;
// urt USB 0 FIFO, S3C2410_UDC_EP0_CSR_IPKRDY 0,USB FIFO S3C2410_UDC_EP0_CSR_IPKRDY
// 0, FIFO , S3C2410_UDC_EP0_CSR_IPKRDY 1。s3c2410_udc_write_fifo
case EP0_OUT_DATA_PHASE:
if ((!_req->length)
|| ((ep_csr & S3C2410_UDC_OCSR1_PKTRDY)
&& s3c2410_udc_read_fifo(ep,
req))) {
dev->ep0state = EP0_IDLE;
req = NULL;
}
break;
default:
local_irq_restore(flags);
return -EL2HLT;
}
} else if ((ep->bEndpointAddress & USB_DIR_IN) != 0
&& (!(ep_csr&S3C2410_UDC_OCSR1_PKTRDY))
&& s3c2410_udc_write_fifo(ep, req)) {
req = NULL;
} else if ((ep_csr & S3C2410_UDC_OCSR1_PKTRDY)
&& fifo_count
&& s3c2410_udc_read_fifo(ep, req)) {
req = NULL;
}
}
/* pio or dma irq handler advances the queue. */
if (likely (req != 0)) // req 0 , likely req 0 ,
list_add_tail(&req->queue, &ep->queue);
local_irq_restore(flags);
dprintk(DEBUG_VERBOSE, "%s ok
", __func__);
return 0;
}
함수 가 composite 로 되 돌 아 왔 습 니 다.setup 에서 코드 를 붙 입 니 다: if (value >= 0) {
req->length = value;
req->zero = value < w_length;
value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
if (value < 0) {
DBG(cdev, "ep_queue --> %d
", value);
req->status = 0;
composite_setup_complete(gadget->ep0, req);
}
}
현재 if (value < 0) 까지 실행 되 었 습 니 다.{위의 분석 value 는 0 이 므 로 아래 코드 는 실행 되 지 않 습 니 다. coposite setup 함수 도 되 돌 아 왔 습 니 다. s3c2410 udc handle ep0 idle 로 돌 아 왔 습 니 다. 오류 가 없 었 기 때문에 s3c2410 udc handle ep0 idle 함수 도 되 돌 아 왔 습 니 다. s3c2410 udc handle ep0 으로 돌 아 왔 습 니 다. 이때 dev - > ep0state 는 EP0 IDLE 상태 입 니 다. 그래서 s3c2410 udc handle ep0 도 되 돌 아 왔 습 니 다.마지막 으로 이 제어 전송 이 완료 되 었 습 니 다. 전송 을 제어 하 는 상태 단 계 는 하드웨어 로 이 루어 집 니 다. FIFO 에 모든 데 이 터 를 기록 하면 EP0 CSR 레지스터 의 DATA END 를 1 로 설정 할 수 있 습 니 다. 하드웨어 는 자동 으로 상태 단 계 를 완성 합 니 다. 또 하 나 는 전송 을 제어 하 는 urt 리 셋 함수 가 매우 간단 합 니 다. 디 버 깅 정보 만 인쇄 할 수 있 습 니 다. 마지막 으로 조정 할 때.s3c2410 udc read fifo 를 사용 할 때 s3c2410 udc read fifo 는 함수 에서 urt 의 반전 함 수 를 호출 합 니 다.이상 은 USB 장치 매 거 진 과정의 두 번 째 단 계 를 분 석 했 습 니 다. Get Descriptor 단계 의 제어 전송 입 니 다. 다른 단 계 는 대동소이 합 니 다. 모두 호스트 에서 시작 한 다음 에 USB 장 치 는 중간 단 계 를 통 해 처 리 됩 니 다. 앞에서 언급 한 6 단 계 를 거 쳐 USB 호스트 는 우리 의 장 치 를 식별 합 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Linux USB Gadget - 장치 매 거 진이 필드 는 struct s3c 2410 을 연결 합 니 다.request 구조의 링크, struct s3c 2410request 는 struct usbrequest 의 간단 한 패 키 징 은 usb 전송 을 대표 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.