Linux USB Gadget - 장치 매 거 진

25948 단어 장치 구동USB
앞서 리 눅 스 USB Gadget 의 소프트웨어 구조 와 각 소프트웨어 층 의 통합 과정 을 소개 했다.각종 등록 함 수 를 거 쳐 Gadget 기능 구동 층, USB 장치 층 과 UDC 바 텀 이 결합 하여 완전한 USB 장 치 를 만 들 었 다.이 장 치 는 호스트 의 매 거 진 을 받 아들 일 준비 가 되 어 있다.USB 장 치 를 소개 하기 전에각 층 통신 에 사용 되 는 데이터 구 조 를 숙지 하고 USB 호스트 에서 USB 장치 드라이버 를 작성 합 니 다. 가장 중요 한 구 조 는 URB 입 니 다. 우 리 는 각종 URB 를 USB 핵심 에 제출 하기 만 하면 핵심 은 자동 으로 우리 의 데 이 터 를 지정 한 장치 로 보 냅 니 다.설비 측 에 도 이와 유사 한 중요 한 데이터 구조 가 있다.이 데이터 구 조 는 urt - usb 입 니 다.request。모든 단점 에는 urt 체인 시계 가 있 고 그 위 에 각종 urt 가 걸 려 있다.바 텀 UDC 의 인 터 럽 트 처리 프로그램 에서 서로 다른 점 에 대해 서로 다른 처리 함 수 를 호출 합 니 다. 한 마디 로 터미널 의 urt 링크 를 처리 하고 하나의 urt 를 처리 하면 미리 설 치 된 리 셋 함 수 를 호출 합 니 다.이것 이 바로 설비 측 데이터 처리 의 절차 다.다음은 usb 분석request 구조:
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 호스트 는 우리 의 장 치 를 식별 합 니 다.

좋은 웹페이지 즐겨찾기